[Tarantool-patches] [PATCH v2 corrected] Increase limits for debug.traceback

Igor Munkin imun at tarantool.org
Sat Jan 25 22:02:15 MSK 2020


Sergey,

Thanks, the patch is nice, except the changes around LUA_IDSIZE_ERR I
was going to reply (but you've sent the second version in a jiffy).

Furthermore I left a few polishing-aimed comments below, please consider
them too.

On 22.01.20, Sergey Voinov wrote:
> Currently debug.traceback cuts out path prefixes
> and removes intermediate frames. This makes it harder
> to debug and navigate to files right from terminal.
> 
> This change increases traceback limits to 25 stack frames
> and maximum source file name length to 128 characters.

AFAICS the change just introduce the compile-time constants to be
tuned for Tarantool built. The defaults are left the same, so please
adjust the commit message.

> 
> There are also changes in main Tarantool trunk in
> cmake/luajit.cmake (see corresponding commit for it).

You can move this remark to the changelog below, since the patch can be
applied w/o the corresponding changes in Tarantool repo.

> 
> Closes: #4581

Please, don't use ':' in gh tags. It just doesn't respect our commit
message style.

> ---
>  Changes in v2:
>  - fixed code and test in accordance with review
> 
>  src/lj_debug.c                         |  8 +--
>  src/luaconf.h                          | 14 ++++-
>  test/tarantool-4581-traceback.test.lua | 79 ++++++++++++++++++++++++++
>  3 files changed, 95 insertions(+), 6 deletions(-)
>  create mode 100755 test/tarantool-4581-traceback.test.lua
> 
> diff --git a/src/lj_debug.c b/src/lj_debug.c
> index 73bd196..e65eb05 100644
> --- a/src/lj_debug.c
> +++ b/src/lj_debug.c
> @@ -332,11 +332,11 @@ void lj_debug_shortname(char *out, GCstr *str, BCLine line)
>      strcpy(out, src);
>    } else {  /* Output [string "string"] or [builtin:name]. */
>      size_t len;  /* Length, up to first control char. */
> -    for (len = 0; len < LUA_IDSIZE-12; len++)
> +    for (len = 0; len < LUA_IDSIZE_ERR-12; len++)
>        if (((const unsigned char *)src)[len] < ' ') break;
>      strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9;
>      if (src[len] != '\0') {  /* Must truncate? */
> -      if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
> +      if (len > LUA_IDSIZE_ERR-15) len = LUA_IDSIZE_ERR-15;
>        strncpy(out, src, len); out += len;
>        strcpy(out, "..."); out += 3;
>      } else {
> @@ -651,8 +651,8 @@ void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, int depth)
>  #endif
>  
>  /* Number of frames for the leading and trailing part of a traceback. */
> -#define TRACEBACK_LEVELS1	12
> -#define TRACEBACK_LEVELS2	10
> +#define TRACEBACK_LEVELS1	LUA_TRACEBACK_LEVELS1
> +#define TRACEBACK_LEVELS2	LUA_TRACEBACK_LEVELS2
>  
>  LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
>  				int level)
> diff --git a/src/luaconf.h b/src/luaconf.h
> index 60cb928..69992b3 100644
> --- a/src/luaconf.h
> +++ b/src/luaconf.h
> @@ -109,9 +109,19 @@
>  #define LUA_MAXINPUT	512	/* Max. input line length. */
>  #endif
>  
> +#ifndef LUA_TRACEBACK_LEVELS1
> +# define LUA_TRACEBACK_LEVELS1	12
> +#endif
> +#ifndef LUA_TRACEBACK_LEVELS2
> +# define LUA_TRACEBACK_LEVELS2	10
> +#endif
> +
>  /* Note: changing the following defines breaks the Lua 5.1 ABI. */
> -#define LUA_INTEGER	ptrdiff_t
> -#define LUA_IDSIZE	60	/* Size of lua_Debug.short_src. */
> +#define LUA_INTEGER		ptrdiff_t
> +#ifndef LUA_IDSIZE
> +# define LUA_IDSIZE		128 /* Size of lua_Debug.short_src. */
> +#endif

Minor: I guess the wrapped LUA_IDSIZE can be placed alongside with the
introduced LUA_TRACEBAKLEVELS{1,2} for better constants locality.

> +#define LUA_IDSIZE_ERR		60  /* Size of error message */

I moved our corresponding discussion from the previous patch below.

|> > I don't get the reason to introduce a separate constant for a single
|> > line sources. Could you please provide a bit more extended rationale?
|>
|> The problem here is that if I allow 128 for size of error messages, all
|> error outputs will be longer and there will be need to fix vast amount
|> of test result outputs (.result files). Also, these long outputs will
|> flood tarantool output. I don't think there is a reason to increase
|> error message size. Do you?

I expect the following comment doesn't look offensive, but in case it does,
I definitely mean nothing abusive.

I still do not understand the reason to introduce a separate constant for
oneline sources.

|> there will be need to fix vast amount of test result outputs (.result
|> files).
AFAIR *.result' files can be adjusted automatically and committed with
the cmake related changes. Since the changes are trivial and atomic I
see nothing bad.

|> Also, these long outputs will flood tarantool output.
As well as long filenames, won't they?

|> Do you?
Yes, I do.

Foremost I see no reason to split the entity (i.e. short source name)
into a separate ones considering with respect to its origin (a source
file or a oneliner). IMHO, this change just introduces excess complexity
with no benefits.

Furthermore, there is no static assert and even comment regarding the
LUA_IDSIZE_ERR value: it have to be less or equal than LUA_IDSIZE. Since
the latter one can be tuned at compile-time there is no guarantee the
buffer overflow doesn't occur.

Considering all said above I'm strictly against introducing a separate
LUA_IDSIZE_ERR constant and urge you to revert the related changes.

>  /*
>  ** Size of lauxlib and io.* on-stack buffers. Weird workaround to avoid using
>  ** unreasonable amounts of stack space, but still retain ABI compatibility.
> diff --git a/test/tarantool-4581-traceback.test.lua b/test/tarantool-4581-traceback.test.lua
> new file mode 100755
> index 0000000..595871b
> --- /dev/null
> +++ b/test/tarantool-4581-traceback.test.lua
> @@ -0,0 +1,79 @@
> +#!/usr/bin/env tarantool
> +
> +---
> +--- gh-4581: Increase limits for debug.traceback
> +---
> +
> +local test = require('tap').test('traceback test')
> +test:plan(1)
> +
> +-- Currently there is no Lua way to detect the values of
> +-- LUA_TRACEBACK_LEVEL1, LUA_TRACEBACK_LEVEL2, LUA_IDSIZE. Therefore
> +-- taking into account the default values configured for Tarantool
> +-- build and considering the existing testing pipeline we can hardcode
> +-- the corresponding values within this test suite to check the output
> +-- produced via debug.backtrace.
> +local LUA_TRACEBACK_LEVEL1 = 25
> +local LUA_TRACEBACK_LEVEL2 = 25
> +
> +local TRACEBACK_MSG1 = 'recursion limit reached!'
> +local TRACEBACK_MSG2 = 'stack traceback:'
> +local TRACEBACK_PATTERN = 'tarantool%-4581%-traceback%.test%.lua:[0-9]+: in .*'
> +
> +-- We use local output variable instead of returning function
> +-- value recursively since luajit optimizes end recursion
> +-- and in that case we would only get 2 stack frames for traceback

Nice!

> +local output
> +
> +-- Recursive function which generates stack frames for debug.traceback
> +local function frec(rec_limit)
> +    if rec_limit <= 0 then
> +        output = debug.traceback(TRACEBACK_MSG1)
> +        -- Strip path from the output and return it
> +        output = output:gsub("[^\n]*/", "")
> +    else
> +        frec(rec_limit - 1)
> +    end
> +end
> +
> +-- Call debug.traceback with specified recursion depth
> +frec(100)
> +
> +local test_ok = false
> +
> +-- Split output into strings
> +local strings = {}
> +for each in output:gmatch("([^\n]+)") do
> +   table.insert(strings, each)
> +end
> +
> +-- Total output string count
> +local count = 0
> +    + 2 -- header
> +    + (LUA_TRACEBACK_LEVEL1-1) -- first part
> +    + 1 -- three dots
> +    + (LUA_TRACEBACK_LEVEL2) -- second part
> +
> +-- Check output strings
> +if count == table.getn(strings) then
> +    for i = 1,count,1 do

Minor: The third parameter is an excess one here, thus I guess it can be
dropped.

> +        local pattern
> +
> +        if i == 1 then 

Minor: Minor: A trailing whitespace is left above.

> +            pattern = TRACEBACK_MSG1
> +        elseif i == 2 then 

Minor: Minor: A trailing whitespace is left above.

> +            pattern = TRACEBACK_MSG2
> +        elseif i ~= LUA_TRACEBACK_LEVEL1 + 2 then
> +            pattern = TRACEBACK_PATTERN
> +        else
> +            pattern = '%.%.%.'
> +        end
> +
> +        test_ok = string.match(strings[i], pattern) ~= nil
> +        if not test_ok then
> +            break
> +        end
> +    end
> +end
> +
> +test:is(test_ok, true)
> -- 
> 2.17.1
> 

-- 
Best regards,
IM


More information about the Tarantool-patches mailing list