Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message.
@ 2022-11-09 17:49 Sergey Kaplun via Tarantool-patches
  2022-11-10  6:02 ` Sergey Kaplun via Tarantool-patches
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2022-11-09 17:49 UTC (permalink / raw)
  To: Maxim Kokryashkin, Igor Munkin; +Cc: tarantool-patches

From: Mike Pall <mike>

Reported by Sergey Kaplun.

(cherry picked from commit ca8d3257bb44e42100c7910c47dcdcf01f494187)

`lj_err_mem()` doesn't set up `L->top` for Lua frames, but uses it for
pushing error message on the stack. So, when we call some routine that
does some allocations, it can raise the OOM error (like `lj_tab_dup()`
in `BC_TDUP`) and this error may corrupt stack for unwind in situations
when `L->top` < `L->base`.

This patch restores `L->top` for Lua frames when raise the error via
`lj_err_mem()`.

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

Resolves tarantool/tarantool#3840
Part of tarantool/tarantool#7230
---

Issues:
* https://github.com/LuaJIT/LuaJIT/issues/906
* https://github.com/tarantool/tarantool/issues/7230
* https://github.com/tarantool/tarantool/issues/3840
PR: https://github.com/tarantool/tarantool/pull/7915
Branch: https://github.com/tarantool/luajit/tree/skaplun/lj-906-fix-err-mem

Red LuaJIT CI for MacOS Release builds is a known issue with self-hosted
runners, as Igor has said before.

 src/lj_err.c                                  |  1 +
 .../lj-906-fix-err-mem.test.lua               | 90 +++++++++++++++++++
 2 files changed, 91 insertions(+)
 create mode 100644 test/tarantool-tests/lj-906-fix-err-mem.test.lua

diff --git a/src/lj_err.c b/src/lj_err.c
index c310daf6..70354489 100644
--- a/src/lj_err.c
+++ b/src/lj_err.c
@@ -546,6 +546,7 @@ LJ_NOINLINE void lj_err_mem(lua_State *L)
 {
   if (L->status == LUA_ERRERR+1)  /* Don't touch the stack during lua_open. */
     lj_vm_unwind_c(L->cframe, LUA_ERRMEM);
+  if (curr_funcisL(L)) L->top = curr_topL(L);
   setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRMEM));
   lj_err_throw(L, LUA_ERRMEM);
 }
diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
new file mode 100644
index 00000000..a139e1c9
--- /dev/null
+++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
@@ -0,0 +1,90 @@
+local tap = require('tap')
+local ffi = require('ffi')
+local table_new = require('table.new')
+
+-- Avoid test to be killed.
+require('utils').skipcond(ffi.abi('gc64'), 'test is not GC64 only')
+
+local test = tap.test('lj-906-fix-err-mem')
+test:plan(1)
+
+local KB = 1024
+local MB = 1024 * KB
+
+-- The maximum available table size, taking into account created
+-- constants for one function.
+local TNEW_SIZE = 511
+
+local gc_anchor = {}
+
+-- This function works until raises the error.
+local function eat_chunks(size)
+  -- Need raise the OOM error inside TDUP, not TNEW, so reserve
+  -- memory for it.
+  -- luacheck: no unused
+  local tnew_anchor = table_new(TNEW_SIZE, 0)
+  while true do
+    table.insert(gc_anchor, ffi.new('char [?]', size))
+  end
+end
+
+-- Function to format inner tab leading to TDUP emitting.
+local function format_inner_tab()
+  local inner_tab = ''
+  local inner_depth = 128
+  -- Repeate table template for TDUP.
+  for _ = 1, inner_depth do
+    inner_tab = inner_tab .. '{a ='
+  end
+  inner_tab = inner_tab .. '{}'
+  for _ = 1, inner_depth do
+    inner_tab = inner_tab .. '},'
+  end
+  return inner_tab
+end
+
+local function format_TDUP_chunk()
+  local big_tab = 'local _ = {\n'
+  local inner_tab = format_inner_tab()
+  for _ = 1, TNEW_SIZE do
+    big_tab = big_tab .. inner_tab .. '\n'
+  end
+  big_tab = big_tab .. '}'
+  return big_tab
+end
+
+local TDUP, err = loadstring(format_TDUP_chunk())
+assert(TDUP, err)
+
+local function frame_before_TDUP()
+  -- Stack slots are needed for coredump in case of misbehaviour.
+  -- luacheck: no unused
+  local frame_slot1, frame_slot2
+  TDUP()
+  return frame_slot1, frame_slot2
+end
+
+collectgarbage()
+collectgarbage('stop')
+
+-- Avoid OOM on traces.
+jit.off()
+
+-- Stack slots are needed for coredump in case of misbehaviour.
+-- luacheck: no unused
+local r, e = pcall(eat_chunks, 8 * MB)
+collectgarbage()
+pcall(eat_chunks, 8 * KB)
+collectgarbage()
+pcall(eat_chunks, 8)
+collectgarbage()
+
+pcall(frame_before_TDUP)
+
+-- Release memory for `tap` functions.
+gc_anchor = nil
+collectgarbage()
+
+test:ok(true, 'correctly throw memory error')
+
+os.exit(test:check() and 0 or 1)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message.
  2022-11-09 17:49 [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message Sergey Kaplun via Tarantool-patches
@ 2022-11-10  6:02 ` Sergey Kaplun via Tarantool-patches
  2022-11-11  8:53 ` Igor Munkin via Tarantool-patches
  2022-11-23  7:51 ` Igor Munkin via Tarantool-patches
  2 siblings, 0 replies; 8+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2022-11-10  6:02 UTC (permalink / raw)
  To: Maxim Kokryashkin, Igor Munkin; +Cc: tarantool-patches

Hi, again!

On 09.11.22, Sergey Kaplun wrote:
> From: Mike Pall <mike>

<snipped>

> +
> +-- Avoid OOM on traces.
> +jit.off()
> +
> +-- Stack slots are needed for coredump in case of misbehaviour.
> +-- luacheck: no unused
> +local r, e = pcall(eat_chunks, 8 * MB)
> +collectgarbage()
> +pcall(eat_chunks, 8 * KB)
> +collectgarbage()
> +pcall(eat_chunks, 8)
> +collectgarbage()

Forgot that `collectgarbage()` (`full_gc()`) enables GC. Fixed. Branch
is force-pushed.

===================================================================
diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
index a139e1c9..f512e802 100644
--- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
+++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
@@ -74,10 +74,13 @@ jit.off()
 -- luacheck: no unused
 local r, e = pcall(eat_chunks, 8 * MB)
 collectgarbage()
+collectgarbage('stop')
 pcall(eat_chunks, 8 * KB)
 collectgarbage()
+collectgarbage('stop')
 pcall(eat_chunks, 8)
 collectgarbage()
+collectgarbage('stop')
 
 pcall(frame_before_TDUP)
 
===================================================================

> +
> +pcall(frame_before_TDUP)
> +
> +-- Release memory for `tap` functions.
> +gc_anchor = nil
> +collectgarbage()
> +
> +test:ok(true, 'correctly throw memory error')
> +
> +os.exit(test:check() and 0 or 1)
> -- 
> 2.34.1
> 

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message.
  2022-11-09 17:49 [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message Sergey Kaplun via Tarantool-patches
  2022-11-10  6:02 ` Sergey Kaplun via Tarantool-patches
@ 2022-11-11  8:53 ` Igor Munkin via Tarantool-patches
  2022-11-11 12:18   ` Sergey Kaplun via Tarantool-patches
  2022-11-23  7:51 ` Igor Munkin via Tarantool-patches
  2 siblings, 1 reply; 8+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2022-11-11  8:53 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

Thanks for the patch!

On 09.11.22, Sergey Kaplun wrote:
> From: Mike Pall <mike>
> 
> Reported by Sergey Kaplun.
> 
> (cherry picked from commit ca8d3257bb44e42100c7910c47dcdcf01f494187)
> 
> `lj_err_mem()` doesn't set up `L->top` for Lua frames, but uses it for

I believe it "doesn't set `L->top` for the current Lua frame, but...",
doesn't it?

> pushing error message on the stack. So, when we call some routine that

Typo: s/some routine/a routine/ or s/some routine/arbitrary routine/.

> does some allocations, it can raise the OOM error (like `lj_tab_dup()`

Strictly saying it's LUA_ERRMEM, not OOM.

> in `BC_TDUP`) and this error may corrupt stack for unwind in situations
> when `L->top` < `L->base`.
> 
> This patch restores `L->top` for Lua frames when raise the error via

Typo: s/raise the error/the error is raised/.

> `lj_err_mem()`.
> 
> Sergey Kaplun:
> * added the description and the test for the problem
> 
> Resolves tarantool/tarantool#3840
> Part of tarantool/tarantool#7230
> ---
> 
> Issues:
> * https://github.com/LuaJIT/LuaJIT/issues/906
> * https://github.com/tarantool/tarantool/issues/7230
> * https://github.com/tarantool/tarantool/issues/3840
> PR: https://github.com/tarantool/tarantool/pull/7915
> Branch: https://github.com/tarantool/luajit/tree/skaplun/lj-906-fix-err-mem
> 
> Red LuaJIT CI for MacOS Release builds is a known issue with self-hosted
> runners, as Igor has said before.

Everything is fixed at the moment, please try to rebase.

> 
>  src/lj_err.c                                  |  1 +
>  .../lj-906-fix-err-mem.test.lua               | 90 +++++++++++++++++++
>  2 files changed, 91 insertions(+)
>  create mode 100644 test/tarantool-tests/lj-906-fix-err-mem.test.lua
> 

<snipped>

> diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
> new file mode 100644
> index 00000000..a139e1c9
> --- /dev/null
> +++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
> @@ -0,0 +1,90 @@
> +local tap = require('tap')
> +local ffi = require('ffi')
> +local table_new = require('table.new')
> +
> +-- Avoid test to be killed.
> +require('utils').skipcond(ffi.abi('gc64'), 'test is not GC64 only')
> +
> +local test = tap.test('lj-906-fix-err-mem')
> +test:plan(1)
> +
> +local KB = 1024
> +local MB = 1024 * KB
> +
> +-- The maximum available table size, taking into account created
> +-- constants for one function.
> +local TNEW_SIZE = 511
> +
> +local gc_anchor = {}
> +
> +-- This function works until raises the error.
> +local function eat_chunks(size)
> +  -- Need raise the OOM error inside TDUP, not TNEW, so reserve
> +  -- memory for it.
> +  -- luacheck: no unused
> +  local tnew_anchor = table_new(TNEW_SIZE, 0)
> +  while true do
> +    table.insert(gc_anchor, ffi.new('char [?]', size))
> +  end
> +end
> +
> +-- Function to format inner tab leading to TDUP emitting.
> +local function format_inner_tab()

Minor: Maybe <make_deep_table(depth)> instead of <format_inner_tab()>?
Just asking, feel free to ignore.

> +  local inner_tab = ''
> +  local inner_depth = 128

Why 128? Please, drop a few words.

> +  -- Repeate table template for TDUP.
> +  for _ = 1, inner_depth do
> +    inner_tab = inner_tab .. '{a ='
> +  end
> +  inner_tab = inner_tab .. '{}'
> +  for _ = 1, inner_depth do
> +    inner_tab = inner_tab .. '},'
> +  end
> +  return inner_tab
> +end
> +

Minor: Same (also think about moving these helpers to utils.*).
Maybe <make_flat_table(size)> instead of <format_TDUP_chunk()>? And
mention TDUP specifics in the comment.

Just asking too, feel free to ignore.

> +local function format_TDUP_chunk()
> +  local big_tab = 'local _ = {\n'
> +  local inner_tab = format_inner_tab()
> +  for _ = 1, TNEW_SIZE do
> +    big_tab = big_tab .. inner_tab .. '\n'
> +  end
> +  big_tab = big_tab .. '}'
> +  return big_tab
> +end
> +
> +local TDUP, err = loadstring(format_TDUP_chunk())
> +assert(TDUP, err)
> +
> +local function frame_before_TDUP()
> +  -- Stack slots are needed for coredump in case of misbehaviour.

Why are they needed? Please drop few more words regarding this.

> +  -- luacheck: no unused
> +  local frame_slot1, frame_slot2
> +  TDUP()
> +  return frame_slot1, frame_slot2
> +end
> +

Minor: I believe you can pack these two lines into something one can
call <janitor>:
| local function janitor()
|   collectgarbage('collect')
|   collectgarbage('stop')
| end

Anyway, you can leave this as is.

> +collectgarbage()
> +collectgarbage('stop')
> +
> +-- Avoid OOM on traces.
> +jit.off()
> +
> +-- Stack slots are needed for coredump in case of misbehaviour.
> +-- luacheck: no unused
> +local r, e = pcall(eat_chunks, 8 * MB)
> +collectgarbage()
> +pcall(eat_chunks, 8 * KB)
> +collectgarbage()
> +pcall(eat_chunks, 8)
> +collectgarbage()
> +
> +pcall(frame_before_TDUP)

Do we need to check the status of the <pcall> above?

> +
> +-- Release memory for `tap` functions.
> +gc_anchor = nil
> +collectgarbage()

Is this step required? I doubt.

> +
> +test:ok(true, 'correctly throw memory error')
> +
> +os.exit(test:check() and 0 or 1)
> -- 
> 2.34.1
> 

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message.
  2022-11-11  8:53 ` Igor Munkin via Tarantool-patches
@ 2022-11-11 12:18   ` Sergey Kaplun via Tarantool-patches
  2022-11-11 13:09     ` Sergey Kaplun via Tarantool-patches
  0 siblings, 1 reply; 8+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2022-11-11 12:18 UTC (permalink / raw)
  To: Igor Munkin; +Cc: tarantool-patches

Hi, Igor!

Thanks for the review!
Welcome back to the ML! :)

Updated remote branch considering your comments.

On 11.11.22, Igor Munkin wrote:
> Sergey,
> 
> Thanks for the patch!
> 
> On 09.11.22, Sergey Kaplun wrote:
> > From: Mike Pall <mike>
> > 
> > Reported by Sergey Kaplun.
> > 
> > (cherry picked from commit ca8d3257bb44e42100c7910c47dcdcf01f494187)
> > 
> > `lj_err_mem()` doesn't set up `L->top` for Lua frames, but uses it for
> 
> I believe it "doesn't set `L->top` for the current Lua frame, but...",
> doesn't it?

Fixed, thanks.

> 
> > pushing error message on the stack. So, when we call some routine that
> 
> Typo: s/some routine/a routine/ or s/some routine/arbitrary routine/.

Fixed.

> 
> > does some allocations, it can raise the OOM error (like `lj_tab_dup()`
> 
> Strictly saying it's LUA_ERRMEM, not OOM.

If you say about naming. Replaced.

> 
> > in `BC_TDUP`) and this error may corrupt stack for unwind in situations
> > when `L->top` < `L->base`.
> > 
> > This patch restores `L->top` for Lua frames when raise the error via
> 
> Typo: s/raise the error/the error is raised/.

Fixed.

> 
> > `lj_err_mem()`.
> > 
> > Sergey Kaplun:
> > * added the description and the test for the problem
> > 
> > Resolves tarantool/tarantool#3840
> > Part of tarantool/tarantool#7230
> > ---
> > 
> > Issues:
> > * https://github.com/LuaJIT/LuaJIT/issues/906
> > * https://github.com/tarantool/tarantool/issues/7230
> > * https://github.com/tarantool/tarantool/issues/3840
> > PR: https://github.com/tarantool/tarantool/pull/7915
> > Branch: https://github.com/tarantool/luajit/tree/skaplun/lj-906-fix-err-mem
> > 
> > Red LuaJIT CI for MacOS Release builds is a known issue with self-hosted
> > runners, as Igor has said before.
> 
> Everything is fixed at the moment, please try to rebase.

Rebased. It works now! Thanks!

> 
> > 
> >  src/lj_err.c                                  |  1 +
> >  .../lj-906-fix-err-mem.test.lua               | 90 +++++++++++++++++++
> >  2 files changed, 91 insertions(+)
> >  create mode 100644 test/tarantool-tests/lj-906-fix-err-mem.test.lua
> > 
> 
> <snipped>
> 
> > diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
> > new file mode 100644
> > index 00000000..a139e1c9
> > --- /dev/null
> > +++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
> > @@ -0,0 +1,90 @@
> > +local tap = require('tap')
> > +local ffi = require('ffi')
> > +local table_new = require('table.new')
> > +
> > +-- Avoid test to be killed.
> > +require('utils').skipcond(ffi.abi('gc64'), 'test is not GC64 only')
> > +
> > +local test = tap.test('lj-906-fix-err-mem')
> > +test:plan(1)
> > +
> > +local KB = 1024
> > +local MB = 1024 * KB
> > +
> > +-- The maximum available table size, taking into account created
> > +-- constants for one function.
> > +local TNEW_SIZE = 511
> > +
> > +local gc_anchor = {}
> > +
> > +-- This function works until raises the error.
> > +local function eat_chunks(size)
> > +  -- Need raise the OOM error inside TDUP, not TNEW, so reserve
> > +  -- memory for it.
> > +  -- luacheck: no unused
> > +  local tnew_anchor = table_new(TNEW_SIZE, 0)
> > +  while true do
> > +    table.insert(gc_anchor, ffi.new('char [?]', size))
> > +  end
> > +end
> > +
> > +-- Function to format inner tab leading to TDUP emitting.
> > +local function format_inner_tab()
> 
> Minor: Maybe <make_deep_table(depth)> instead of <format_inner_tab()>?
> Just asking, feel free to ignore.

Fixed.

> 
> > +  local inner_tab = ''
> > +  local inner_depth = 128
> 
> Why 128? Please, drop a few words.

Added.

> 
> > +  -- Repeate table template for TDUP.
> > +  for _ = 1, inner_depth do
> > +    inner_tab = inner_tab .. '{a ='
> > +  end
> > +  inner_tab = inner_tab .. '{}'
> > +  for _ = 1, inner_depth do
> > +    inner_tab = inner_tab .. '},'
> > +  end
> > +  return inner_tab
> > +end
> > +
> 
> Minor: Same (also think about moving these helpers to utils.*).
> Maybe <make_flat_table(size)> instead of <format_TDUP_chunk()>?

IMHO, it's too specific to use this function test-wide, so I just
keep it as is. If we need similar functionality somewhere else, we
can move this function to <utils.lua> later.

So ignore here.

>                                                                 And
> mention TDUP specifics in the comment.

Fixed.

> 
> Just asking too, feel free to ignore.
> 
> > +local function format_TDUP_chunk()
> > +  local big_tab = 'local _ = {\n'
> > +  local inner_tab = format_inner_tab()
> > +  for _ = 1, TNEW_SIZE do
> > +    big_tab = big_tab .. inner_tab .. '\n'
> > +  end
> > +  big_tab = big_tab .. '}'
> > +  return big_tab
> > +end
> > +
> > +local TDUP, err = loadstring(format_TDUP_chunk())
> > +assert(TDUP, err)
> > +
> > +local function frame_before_TDUP()
> > +  -- Stack slots are needed for coredump in case of misbehaviour.
> 
> Why are they needed? Please drop few more words regarding this.

Hmm, I obscure coredump without them too (because of rewriting the
other stack slot). But the frame before TDUP is really needed to rewrite
pcall frame. Fixed, and added the comment.

All minor patches about comments above are done via the following
iterative patch:

===================================================================
diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
index f512e802..0ec1b30e 100644
--- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
+++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
@@ -12,7 +12,7 @@ local KB = 1024
 local MB = 1024 * KB
 
 -- The maximum available table size, taking into account created
--- constants for one function.
+-- constants for one function and nested level.
 local TNEW_SIZE = 511
 
 local gc_anchor = {}
@@ -29,9 +29,8 @@ local function eat_chunks(size)
 end
 
 -- Function to format inner tab leading to TDUP emitting.
-local function format_inner_tab()
+local function make_flat_table(inner_depth)
   local inner_tab = ''
-  local inner_depth = 128
   -- Repeate table template for TDUP.
   for _ = 1, inner_depth do
     inner_tab = inner_tab .. '{a ='
@@ -43,9 +42,14 @@ local function format_inner_tab()
   return inner_tab
 end
 
+-- The `lj_err_mem()` doesn't fix `L->top`, when called from
+-- helper function (like `lj_tab_dup()`) before the patch.
+-- This function creates a chunk with many BC_TDUP inside.
 local function format_TDUP_chunk()
   local big_tab = 'local _ = {\n'
-  local inner_tab = format_inner_tab()
+  -- The maximum available table size, taking into account created
+  -- constants for one function and nested level.
+  local inner_tab = make_flat_table(128)
   for _ = 1, TNEW_SIZE do
     big_tab = big_tab .. inner_tab .. '\n'
   end
@@ -56,12 +60,10 @@ end
 local TDUP, err = loadstring(format_TDUP_chunk())
 assert(TDUP, err)
 
+-- Function to create the additional frame after to be rewrited
+-- one in case of `lj_err_mem()` misbehaviour.
 local function frame_before_TDUP()
-  -- Stack slots are needed for coredump in case of misbehaviour.
-  -- luacheck: no unused
-  local frame_slot1, frame_slot2
   TDUP()
-  return frame_slot1, frame_slot2
 end
 
 collectgarbage()
===================================================================


> 
> > +  -- luacheck: no unused
> > +  local frame_slot1, frame_slot2
> > +  TDUP()
> > +  return frame_slot1, frame_slot2
> > +end
> > +
> 
> Minor: I believe you can pack these two lines into something one can
> call <janitor>:
> | local function janitor()
> |   collectgarbage('collect')
> |   collectgarbage('stop')
> | end
> 
> Anyway, you can leave this as is.

Added, thanks!
See the iterative patch below.
===================================================================
diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
index 519e6bf6..7dbc1614 100644
--- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
+++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
@@ -66,8 +66,12 @@ local function frame_before_TDUP()
   TDUP()
 end
 
-collectgarbage()
-collectgarbage('stop')
+local function janitor()
+  collectgarbage('collect')
+  collectgarbage('stop')
+end
+
+janitor()
 
 -- Avoid OOM on traces.
 jit.off()
@@ -75,14 +79,11 @@ jit.off()
 -- Stack slots are needed for coredump in case of misbehaviour.
 -- luacheck: no unused
 local r, e = pcall(eat_chunks, 8 * MB)
-collectgarbage()
-collectgarbage('stop')
+janitor()
 pcall(eat_chunks, 8 * KB)
-collectgarbage()
-collectgarbage('stop')
+janitor()
 pcall(eat_chunks, 8)
-collectgarbage()
-collectgarbage('stop')
+janitor()
 
 pcall(frame_before_TDUP)
===================================================================

 
> 
> > +collectgarbage()
> > +collectgarbage('stop')
> > +
> > +-- Avoid OOM on traces.
> > +jit.off()
> > +
> > +-- Stack slots are needed for coredump in case of misbehaviour.
> > +-- luacheck: no unused
> > +local r, e = pcall(eat_chunks, 8 * MB)
> > +collectgarbage()
> > +pcall(eat_chunks, 8 * KB)
> > +collectgarbage()
> > +pcall(eat_chunks, 8)
> > +collectgarbage()
> > +
> > +pcall(frame_before_TDUP)
> 
> Do we need to check the status of the <pcall> above?

I suppose no. As we disscussed offline the test may be flaky (false
positive, when we can alloc all tables) due to memory allocations.
Also, this part is very fragile, and we don't want to fix test later by
removing this check the status of the `pcall()`.

> 
> > +
> > +-- Release memory for `tap` functions.
> > +gc_anchor = nil
> > +collectgarbage()
> 
> Is this step required? I doubt.

Yes it is. Without it we may get the OOM error inside `test:ok()` or
`test:check()` functions (I faced it on my local machine, when rewrite
this test).

> 
> > +
> > +test:ok(true, 'correctly throw memory error')
> > +
> > +os.exit(test:check() and 0 or 1)
> > -- 
> > 2.34.1
> > 
> 
> -- 
> Best regards,
> IM

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message.
  2022-11-11 12:18   ` Sergey Kaplun via Tarantool-patches
@ 2022-11-11 13:09     ` Sergey Kaplun via Tarantool-patches
  2022-11-16 12:30       ` Maxim Kokryashkin via Tarantool-patches
  2022-11-22 17:08       ` Igor Munkin via Tarantool-patches
  0 siblings, 2 replies; 8+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2022-11-11 13:09 UTC (permalink / raw)
  To: Igor Munkin, tarantool-patches

Hi, again!

Added minor fixes.

On 11.11.22, Sergey Kaplun via Tarantool-patches wrote:

<snipped>

> ===================================================================
> diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
> index f512e802..0ec1b30e 100644
> --- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
> +++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
> @@ -12,7 +12,7 @@ local KB = 1024
>  local MB = 1024 * KB
>  
>  -- The maximum available table size, taking into account created
> --- constants for one function.
> +-- constants for one function and nested level.
>  local TNEW_SIZE = 511
>  
>  local gc_anchor = {}
> @@ -29,9 +29,8 @@ local function eat_chunks(size)
>  end
>  
>  -- Function to format inner tab leading to TDUP emitting.
> -local function format_inner_tab()
> +local function make_flat_table(inner_depth)

Should be deep_table, obviously.

===================================================================
diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
index 7dbc1614..69f74893 100644
--- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
+++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
@@ -29,7 +29,7 @@ local function eat_chunks(size)
 end
 
 -- Function to format inner tab leading to TDUP emitting.
-local function make_flat_table(inner_depth)
+local function make_deep_table(inner_depth)
   local inner_tab = ''
   -- Repeate table template for TDUP.
   for _ = 1, inner_depth do
@@ -49,7 +49,7 @@ local function format_TDUP_chunk()
   local big_tab = 'local _ = {\n'
   -- The maximum available table size, taking into account created
   -- constants for one function and nested level.
-  local inner_tab = make_flat_table(128)
+  local inner_tab = make_deep_table(128)
   for _ = 1, TNEW_SIZE do
     big_tab = big_tab .. inner_tab .. '\n'
   end
===================================================================

>    local inner_tab = ''
> -  local inner_depth = 128
>    -- Repeate table template for TDUP.
>    for _ = 1, inner_depth do
>      inner_tab = inner_tab .. '{a ='
> @@ -43,9 +42,14 @@ local function format_inner_tab()
>    return inner_tab
>  end
>  
> +-- The `lj_err_mem()` doesn't fix `L->top`, when called from
> +-- helper function (like `lj_tab_dup()`) before the patch.
> +-- This function creates a chunk with many BC_TDUP inside.
>  local function format_TDUP_chunk()
>    local big_tab = 'local _ = {\n'
> -  local inner_tab = format_inner_tab()
> +  -- The maximum available table size, taking into account created
> +  -- constants for one function and nested level.
> +  local inner_tab = make_flat_table(128)
>    for _ = 1, TNEW_SIZE do
>      big_tab = big_tab .. inner_tab .. '\n'
>    end
> @@ -56,12 +60,10 @@ end
>  local TDUP, err = loadstring(format_TDUP_chunk())
>  assert(TDUP, err)
>  
> +-- Function to create the additional frame after to be rewrited
> +-- one in case of `lj_err_mem()` misbehaviour.

Also, minor comments fixes and renaming.
===================================================================
diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
index 69f74893..f4ec6620 100644
--- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
+++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
@@ -45,7 +45,7 @@ end
 -- The `lj_err_mem()` doesn't fix `L->top`, when called from
 -- helper function (like `lj_tab_dup()`) before the patch.
 -- This function creates a chunk with many BC_TDUP inside.
-local function format_TDUP_chunk()
+local function make_TDUP_chunk()
   local big_tab = 'local _ = {\n'
   -- The maximum available table size, taking into account created
   -- constants for one function and nested level.
@@ -57,11 +57,11 @@ local function format_TDUP_chunk()
   return big_tab
 end
 
-local TDUP, err = loadstring(format_TDUP_chunk())
+local TDUP, err = loadstring(make_TDUP_chunk())
 assert(TDUP, err)
 
--- Function to create the additional frame after to be rewrited
--- one in case of `lj_err_mem()` misbehaviour.
+-- Function  to create the additional frame to be rewritten later
+-- in case of `lj_err_mem()` misbehaviour.
 local function frame_before_TDUP()
   TDUP()
 end
===================================================================

Branch is force-pushed.
>  local function frame_before_TDUP()
> -  -- Stack slots are needed for coredump in case of misbehaviour.
> -  -- luacheck: no unused
> -  local frame_slot1, frame_slot2
>    TDUP()
> -  return frame_slot1, frame_slot2
>  end
>  
>  collectgarbage()
> ===================================================================
> 
> 
> > 
> > > +  -- luacheck: no unused
> > > +  local frame_slot1, frame_slot2
> > > +  TDUP()
> > > +  return frame_slot1, frame_slot2
> > > +end
> > > +
> > 
> > Minor: I believe you can pack these two lines into something one can
> > call <janitor>:
> > | local function janitor()
> > |   collectgarbage('collect')
> > |   collectgarbage('stop')
> > | end
> > 
> > Anyway, you can leave this as is.
> 
> Added, thanks!
> See the iterative patch below.
> ===================================================================
> diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
> index 519e6bf6..7dbc1614 100644
> --- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
> +++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
> @@ -66,8 +66,12 @@ local function frame_before_TDUP()
>    TDUP()
>  end
>  
> -collectgarbage()
> -collectgarbage('stop')
> +local function janitor()
> +  collectgarbage('collect')
> +  collectgarbage('stop')
> +end
> +
> +janitor()
>  
>  -- Avoid OOM on traces.
>  jit.off()
> @@ -75,14 +79,11 @@ jit.off()
>  -- Stack slots are needed for coredump in case of misbehaviour.
>  -- luacheck: no unused
>  local r, e = pcall(eat_chunks, 8 * MB)
> -collectgarbage()
> -collectgarbage('stop')
> +janitor()
>  pcall(eat_chunks, 8 * KB)
> -collectgarbage()
> -collectgarbage('stop')
> +janitor()
>  pcall(eat_chunks, 8)
> -collectgarbage()
> -collectgarbage('stop')
> +janitor()
>  
>  pcall(frame_before_TDUP)
> ===================================================================
> 
>  
> > 
> > > +collectgarbage()
> > > +collectgarbage('stop')
> > > +
> > > +-- Avoid OOM on traces.
> > > +jit.off()
> > > +
> > > +-- Stack slots are needed for coredump in case of misbehaviour.
> > > +-- luacheck: no unused
> > > +local r, e = pcall(eat_chunks, 8 * MB)
> > > +collectgarbage()
> > > +pcall(eat_chunks, 8 * KB)
> > > +collectgarbage()
> > > +pcall(eat_chunks, 8)
> > > +collectgarbage()
> > > +
> > > +pcall(frame_before_TDUP)
> > 
> > Do we need to check the status of the <pcall> above?
> 
> I suppose no. As we disscussed offline the test may be flaky (false
> positive, when we can alloc all tables) due to memory allocations.
> Also, this part is very fragile, and we don't want to fix test later by
> removing this check the status of the `pcall()`.
> 
> > 
> > > +
> > > +-- Release memory for `tap` functions.
> > > +gc_anchor = nil
> > > +collectgarbage()
> > 
> > Is this step required? I doubt.
> 
> Yes it is. Without it we may get the OOM error inside `test:ok()` or
> `test:check()` functions (I faced it on my local machine, when rewrite
> this test).
> 
> > 
> > > +
> > > +test:ok(true, 'correctly throw memory error')
> > > +
> > > +os.exit(test:check() and 0 or 1)
> > > -- 
> > > 2.34.1
> > > 
> > 
> > -- 
> > Best regards,
> > IM
> 
> -- 
> Best regards,
> Sergey Kaplun

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches]  [PATCH luajit] Ensure correct stack top for OOM error message.
  2022-11-11 13:09     ` Sergey Kaplun via Tarantool-patches
@ 2022-11-16 12:30       ` Maxim Kokryashkin via Tarantool-patches
  2022-11-22 17:08       ` Igor Munkin via Tarantool-patches
  1 sibling, 0 replies; 8+ messages in thread
From: Maxim Kokryashkin via Tarantool-patches @ 2022-11-16 12:30 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

[-- Attachment #1: Type: text/plain, Size: 8140 bytes --]


Hi, Sergey!
Thanks for the patch!
LGTM
> 
>>Hi, again!
>>
>>Added minor fixes.
>>
>>On 11.11.22, Sergey Kaplun via Tarantool-patches wrote:
>>
>><snipped>
>>
>>> ===================================================================
>>> diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>> index f512e802..0ec1b30e 100644
>>> --- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>> +++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>> @@ -12,7 +12,7 @@ local KB = 1024
>>> local MB = 1024 * KB
>>>
>>> -- The maximum available table size, taking into account created
>>> --- constants for one function.
>>> +-- constants for one function and nested level.
>>> local TNEW_SIZE = 511
>>>
>>> local gc_anchor = {}
>>> @@ -29,9 +29,8 @@ local function eat_chunks(size)
>>> end
>>>
>>> -- Function to format inner tab leading to TDUP emitting.
>>> -local function format_inner_tab()
>>> +local function make_flat_table(inner_depth)
>>
>>Should be deep_table, obviously.
>>
>>===================================================================
>>diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>index 7dbc1614..69f74893 100644
>>--- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>+++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>@@ -29,7 +29,7 @@ local function eat_chunks(size)
>> end
>> 
>> -- Function to format inner tab leading to TDUP emitting.
>>-local function make_flat_table(inner_depth)
>>+local function make_deep_table(inner_depth)
>>   local inner_tab = ''
>>   -- Repeate table template for TDUP.
>>   for _ = 1, inner_depth do
>>@@ -49,7 +49,7 @@ local function format_TDUP_chunk()
>>   local big_tab = 'local _ = {\n'
>>   -- The maximum available table size, taking into account created
>>   -- constants for one function and nested level.
>>- local inner_tab = make_flat_table(128)
>>+ local inner_tab = make_deep_table(128)
>>   for _ = 1, TNEW_SIZE do
>>     big_tab = big_tab .. inner_tab .. '\n'
>>   end
>>===================================================================
>>
>>> local inner_tab = ''
>>> - local inner_depth = 128
>>> -- Repeate table template for TDUP.
>>> for _ = 1, inner_depth do
>>> inner_tab = inner_tab .. '{a ='
>>> @@ -43,9 +42,14 @@ local function format_inner_tab()
>>> return inner_tab
>>> end
>>>
>>> +-- The `lj_err_mem()` doesn't fix `L->top`, when called from
>>> +-- helper function (like `lj_tab_dup()`) before the patch.
>>> +-- This function creates a chunk with many BC_TDUP inside.
>>> local function format_TDUP_chunk()
>>> local big_tab = 'local _ = {\n'
>>> - local inner_tab = format_inner_tab()
>>> + -- The maximum available table size, taking into account created
>>> + -- constants for one function and nested level.
>>> + local inner_tab = make_flat_table(128)
>>> for _ = 1, TNEW_SIZE do
>>> big_tab = big_tab .. inner_tab .. '\n'
>>> end
>>> @@ -56,12 +60,10 @@ end
>>> local TDUP, err = loadstring(format_TDUP_chunk())
>>> assert(TDUP, err)
>>>
>>> +-- Function to create the additional frame after to be rewrited
>>> +-- one in case of `lj_err_mem()` misbehaviour.
>>
>>Also, minor comments fixes and renaming.
>>===================================================================
>>diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>index 69f74893..f4ec6620 100644
>>--- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>+++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>@@ -45,7 +45,7 @@ end
>> -- The `lj_err_mem()` doesn't fix `L->top`, when called from
>> -- helper function (like `lj_tab_dup()`) before the patch.
>> -- This function creates a chunk with many BC_TDUP inside.
>>-local function format_TDUP_chunk()
>>+local function make_TDUP_chunk()
>>   local big_tab = 'local _ = {\n'
>>   -- The maximum available table size, taking into account created
>>   -- constants for one function and nested level.
>>@@ -57,11 +57,11 @@ local function format_TDUP_chunk()
>>   return big_tab
>> end
>> 
>>-local TDUP, err = loadstring(format_TDUP_chunk())
>>+local TDUP, err = loadstring(make_TDUP_chunk())
>> assert(TDUP, err)
>> 
>>--- Function to create the additional frame after to be rewrited
>>--- one in case of `lj_err_mem()` misbehaviour.
>>+-- Function to create the additional frame to be rewritten later
>>+-- in case of `lj_err_mem()` misbehaviour.
>> local function frame_before_TDUP()
>>   TDUP()
>> end
>>===================================================================
>>
>>Branch is force-pushed.
>>> local function frame_before_TDUP()
>>> - -- Stack slots are needed for coredump in case of misbehaviour.
>>> - -- luacheck: no unused
>>> - local frame_slot1, frame_slot2
>>> TDUP()
>>> - return frame_slot1, frame_slot2
>>> end
>>>
>>> collectgarbage()
>>> ===================================================================
>>>
>>>
>>> >
>>> > > + -- luacheck: no unused
>>> > > + local frame_slot1, frame_slot2
>>> > > + TDUP()
>>> > > + return frame_slot1, frame_slot2
>>> > > +end
>>> > > +
>>> >
>>> > Minor: I believe you can pack these two lines into something one can
>>> > call <janitor>:
>>> > | local function janitor()
>>> > | collectgarbage('collect')
>>> > | collectgarbage('stop')
>>> > | end
>>> >
>>> > Anyway, you can leave this as is.
>>>
>>> Added, thanks!
>>> See the iterative patch below.
>>> ===================================================================
>>> diff --git a/test/tarantool-tests/lj-906-fix-err-mem.test.lua b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>> index 519e6bf6..7dbc1614 100644
>>> --- a/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>> +++ b/test/tarantool-tests/lj-906-fix-err-mem.test.lua
>>> @@ -66,8 +66,12 @@ local function frame_before_TDUP()
>>> TDUP()
>>> end
>>>
>>> -collectgarbage()
>>> -collectgarbage('stop')
>>> +local function janitor()
>>> + collectgarbage('collect')
>>> + collectgarbage('stop')
>>> +end
>>> +
>>> +janitor()
>>>
>>> -- Avoid OOM on traces.
>>> jit.off()
>>> @@ -75,14 +79,11 @@ jit.off()
>>> -- Stack slots are needed for coredump in case of misbehaviour.
>>> -- luacheck: no unused
>>> local r, e = pcall(eat_chunks, 8 * MB)
>>> -collectgarbage()
>>> -collectgarbage('stop')
>>> +janitor()
>>> pcall(eat_chunks, 8 * KB)
>>> -collectgarbage()
>>> -collectgarbage('stop')
>>> +janitor()
>>> pcall(eat_chunks, 8)
>>> -collectgarbage()
>>> -collectgarbage('stop')
>>> +janitor()
>>>
>>> pcall(frame_before_TDUP)
>>> ===================================================================
>>>
>>>
>>> >
>>> > > +collectgarbage()
>>> > > +collectgarbage('stop')
>>> > > +
>>> > > +-- Avoid OOM on traces.
>>> > > +jit.off()
>>> > > +
>>> > > +-- Stack slots are needed for coredump in case of misbehaviour.
>>> > > +-- luacheck: no unused
>>> > > +local r, e = pcall(eat_chunks, 8 * MB)
>>> > > +collectgarbage()
>>> > > +pcall(eat_chunks, 8 * KB)
>>> > > +collectgarbage()
>>> > > +pcall(eat_chunks, 8)
>>> > > +collectgarbage()
>>> > > +
>>> > > +pcall(frame_before_TDUP)
>>> >
>>> > Do we need to check the status of the <pcall> above?
>>>
>>> I suppose no. As we disscussed offline the test may be flaky (false
>>> positive, when we can alloc all tables) due to memory allocations.
>>> Also, this part is very fragile, and we don't want to fix test later by
>>> removing this check the status of the `pcall()`.
>>>
>>> >
>>> > > +
>>> > > +-- Release memory for `tap` functions.
>>> > > +gc_anchor = nil
>>> > > +collectgarbage()
>>> >
>>> > Is this step required? I doubt.
>>>
>>> Yes it is. Without it we may get the OOM error inside `test:ok()` or
>>> `test:check()` functions (I faced it on my local machine, when rewrite
>>> this test).
>>>
>>> >
>>> > > +
>>> > > +test:ok(true, 'correctly throw memory error')
>>> > > +
>>> > > +os.exit(test:check() and 0 or 1)
>>> > > --
>>> > > 2.34.1
>>> > >
>>> >
>>> > --
>>> > Best regards,
>>> > IM
>>>
>>> --
>>> Best regards,
>>> Sergey Kaplun
>>
>>--
>>Best regards,
>>Sergey Kaplun
> 
Best regards,
Maxim Kokryashkin

[-- Attachment #2: Type: text/html, Size: 10017 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message.
  2022-11-11 13:09     ` Sergey Kaplun via Tarantool-patches
  2022-11-16 12:30       ` Maxim Kokryashkin via Tarantool-patches
@ 2022-11-22 17:08       ` Igor Munkin via Tarantool-patches
  1 sibling, 0 replies; 8+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2022-11-22 17:08 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

Thanks for the fixes! LGTM.

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message.
  2022-11-09 17:49 [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message Sergey Kaplun via Tarantool-patches
  2022-11-10  6:02 ` Sergey Kaplun via Tarantool-patches
  2022-11-11  8:53 ` Igor Munkin via Tarantool-patches
@ 2022-11-23  7:51 ` Igor Munkin via Tarantool-patches
  2 siblings, 0 replies; 8+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2022-11-23  7:51 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

I've checked the patches into all long-term branches in tarantool/luajit
and bumped a new version in master, 2.10 and 1.10.

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-11-23  8:05 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-09 17:49 [Tarantool-patches] [PATCH luajit] Ensure correct stack top for OOM error message Sergey Kaplun via Tarantool-patches
2022-11-10  6:02 ` Sergey Kaplun via Tarantool-patches
2022-11-11  8:53 ` Igor Munkin via Tarantool-patches
2022-11-11 12:18   ` Sergey Kaplun via Tarantool-patches
2022-11-11 13:09     ` Sergey Kaplun via Tarantool-patches
2022-11-16 12:30       ` Maxim Kokryashkin via Tarantool-patches
2022-11-22 17:08       ` Igor Munkin via Tarantool-patches
2022-11-23  7:51 ` Igor Munkin via Tarantool-patches

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox