Skip to content

Commit

Permalink
FFI: Fix pragma push stack limit check and throw on overflow.
Browse files Browse the repository at this point in the history
Reported by Sergey Kaplun.

(cherry-picked from commit 433d7e8)

`cp->packstack` is the array of size `CPARSE_MAX_PACKSTACK` (7). Before
the patch, `cp->curpack` is checked to be less than
`CPARSE_MAX_PACKSTACK`, but then `cp->packstack` is accessed at
`cp->curpack + 1`, which is out of bounds, so `cp->curpack` value is
overwritten.

This patch fixes a condition and also adds the error throw when counter
is overflow (instead of rewriting a top `cp->packstack` value).

Sergey Kaplun:
* added the description and the test for the problem

Resolves tarantool/tarantool#9339
Part of tarantool/tarantool#9145
  • Loading branch information
Mike Pall authored and Buristan committed Nov 8, 2023
1 parent 52e7daa commit 9c9500c
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/lj_cparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1777,9 +1777,11 @@ static void cp_pragma(CPState *cp, BCLine pragmaline)
cp_check(cp, '(');
if (cp->tok == CTOK_IDENT) {
if (cp_str_is(cp->str, "push")) {
if (cp->curpack < CPARSE_MAX_PACKSTACK) {
if (cp->curpack < CPARSE_MAX_PACKSTACK-1) {
cp->packstack[cp->curpack+1] = cp->packstack[cp->curpack];
cp->curpack++;
} else {
cp_errmsg(cp, cp->tok, LJ_ERR_XLEVELS);
}
} else if (cp_str_is(cp->str, "pop")) {
if (cp->curpack > 0) cp->curpack--;
Expand Down
44 changes: 44 additions & 0 deletions test/tarantool-tests/lj-1114-ffi-pragma-pack.test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
local tap = require('tap')

-- Test file to demonstrate LuaJIT incorrect parsing of `#pragma`
-- directive via FFI.
-- See also: https://github.com/LuaJIT/LuaJIT/issues/1114.

local test = tap.test('lj-1114-ffi-pragma-pack')
local ffi = require 'ffi'

test:plan(2)

-- `cp->packstack` is the array of size `CPARSE_MAX_PACKSTACK`
-- (7). Before the patch, `cp->curpack` is checked to be less than
-- `CPARSE_MAX_PACKSTACK`, but then `cp->packstack` is accessed at
-- `cp->curpack + 1`, which is out of bounds, so `cp->curpack`
-- value is overwritten.
-- As a result, the incorrect pack value (1) is chosen after pop.
-- After the patch, the error is thrown in the case of overflow
-- (instead of rewriting the top pack slot value), so we use the
-- wrapper to catch the error.
local function ffi_cdef_wp()
ffi.cdef[[
#pragma pack(push, 1)
#pragma pack(push, 1)
#pragma pack(push, 1)
#pragma pack(push, 1)
#pragma pack(push, 8)
#pragma pack(push, 8)
#pragma pack(push, 8)
#pragma pack(pop)
struct aligned_struct {uint64_t a; uint8_t b;};
]]

-- Got 9 in case of buffer overflow.
return ffi.sizeof(ffi.new('struct aligned_struct'))
end

local err, msg = pcall(ffi_cdef_wp)

test:ok(not err, 'the error is thrown when couner overflows')
test:like(msg, 'chunk has too many syntax levels',
'the error message is correct')

test:done(true)

0 comments on commit 9c9500c

Please sign in to comment.