diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-02-09 14:00:05 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-02-09 14:00:05 -0300 |
commit | 4e47f81188d37e29027158b76271d02a781242e2 (patch) | |
tree | c360912d1901acf8371390cc1f716278e5d91bb4 /testes | |
parent | c63e5d212bc5dec1b1c749e3f07b42cd83081826 (diff) | |
download | lua-4e47f81188d37e29027158b76271d02a781242e2.tar.gz lua-4e47f81188d37e29027158b76271d02a781242e2.tar.bz2 lua-4e47f81188d37e29027158b76271d02a781242e2.zip |
New implementation for to-be-closed variables
To-be-closed variables are linked in their own list, embedded into the
stack elements. (Due to alignment, this information does not change
the size of the stack elements in most architectures.) This new list
does not produce garbage and avoids memory errors when creating tbc
variables.
Diffstat (limited to 'testes')
-rw-r--r-- | testes/locals.lua | 49 |
1 files changed, 41 insertions, 8 deletions
diff --git a/testes/locals.lua b/testes/locals.lua index a25b2b9f..446ec13a 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -529,6 +529,40 @@ local function checktable (t1, t2) | |||
529 | end | 529 | end |
530 | 530 | ||
531 | 531 | ||
532 | do -- test for tbc variable high in the stack | ||
533 | |||
534 | -- function to force a stack overflow | ||
535 | local function overflow (n) | ||
536 | overflow(n + 1) | ||
537 | end | ||
538 | |||
539 | -- error handler will create tbc variable handling a stack overflow, | ||
540 | -- high in the stack | ||
541 | local function errorh (m) | ||
542 | assert(string.find(m, "stack overflow")) | ||
543 | local x <close> = func2close(function (o) o[1] = 10 end) | ||
544 | return x | ||
545 | end | ||
546 | |||
547 | local flag | ||
548 | local st, obj | ||
549 | -- run test in a coroutine so as not to swell the main stack | ||
550 | local co = coroutine.wrap(function () | ||
551 | -- tbc variable down the stack | ||
552 | local y <close> = func2close(function (obj, msg) | ||
553 | assert(msg == nil) | ||
554 | obj[1] = 100 | ||
555 | flag = obj | ||
556 | end) | ||
557 | collectgarbage("stop") | ||
558 | st, obj = xpcall(overflow, errorh, 0) | ||
559 | collectgarbage("restart") | ||
560 | end) | ||
561 | co() | ||
562 | assert(not st and obj[1] == 10 and flag[1] == 100) | ||
563 | end | ||
564 | |||
565 | |||
532 | if rawget(_G, "T") then | 566 | if rawget(_G, "T") then |
533 | 567 | ||
534 | -- memory error inside closing function | 568 | -- memory error inside closing function |
@@ -563,13 +597,13 @@ if rawget(_G, "T") then | |||
563 | 597 | ||
564 | local function test () | 598 | local function test () |
565 | local x <close> = enter(0) -- set a memory limit | 599 | local x <close> = enter(0) -- set a memory limit |
566 | -- creation of previous upvalue will raise a memory error | 600 | local y = {} -- raise a memory error |
567 | assert(false) -- should not run | ||
568 | end | 601 | end |
569 | 602 | ||
570 | local _, msg = pcall(test) | 603 | local _, msg = pcall(test) |
571 | assert(msg == "not enough memory" and closemsg == "not enough memory") | 604 | assert(msg == "not enough memory" and closemsg == "not enough memory") |
572 | 605 | ||
606 | |||
573 | -- repeat test with extra closing upvalues | 607 | -- repeat test with extra closing upvalues |
574 | local function test () | 608 | local function test () |
575 | local xxx <close> = func2close(function (self, msg) | 609 | local xxx <close> = func2close(function (self, msg) |
@@ -580,8 +614,7 @@ if rawget(_G, "T") then | |||
580 | assert(msg == "not enough memory"); | 614 | assert(msg == "not enough memory"); |
581 | end) | 615 | end) |
582 | local x <close> = enter(0) -- set a memory limit | 616 | local x <close> = enter(0) -- set a memory limit |
583 | -- creation of previous upvalue will raise a memory error | 617 | local y = {} -- raise a memory error |
584 | os.exit(false) -- should not run | ||
585 | end | 618 | end |
586 | 619 | ||
587 | local _, msg = pcall(test) | 620 | local _, msg = pcall(test) |
@@ -607,7 +640,7 @@ if rawget(_G, "T") then | |||
607 | -- concat this table needs two buffer resizes (one for each 's') | 640 | -- concat this table needs two buffer resizes (one for each 's') |
608 | local a = {s, s} | 641 | local a = {s, s} |
609 | 642 | ||
610 | collectgarbage() | 643 | collectgarbage(); collectgarbage() |
611 | 644 | ||
612 | m = T.totalmem() | 645 | m = T.totalmem() |
613 | collectgarbage("stop") | 646 | collectgarbage("stop") |
@@ -630,7 +663,7 @@ if rawget(_G, "T") then | |||
630 | -- second buffer was released by 'toclose' | 663 | -- second buffer was released by 'toclose' |
631 | assert(T.totalmem() - m <= extra) | 664 | assert(T.totalmem() - m <= extra) |
632 | 665 | ||
633 | -- userdata, upvalue, buffer, buffer, final string | 666 | -- userdata, buffer, buffer, final string |
634 | T.totalmem(m + 4*lim + extra) | 667 | T.totalmem(m + 4*lim + extra) |
635 | assert(#table.concat(a) == 2*lim) | 668 | assert(#table.concat(a) == 2*lim) |
636 | 669 | ||
@@ -753,8 +786,8 @@ do | |||
753 | checktable({co()}, {true, 10, 20, 30}) | 786 | checktable({co()}, {true, 10, 20, 30}) |
754 | checktable(trace, {"nowX", "z1", "z2", "nowY", "y1", "y2", "x1", "x2"}) | 787 | checktable(trace, {"nowX", "z1", "z2", "nowY", "y1", "y2", "x1", "x2"}) |
755 | 788 | ||
756 | end | 789 | end |
757 | 790 | ||
758 | 791 | ||
759 | do | 792 | do |
760 | -- yielding inside closing metamethods after an error | 793 | -- yielding inside closing metamethods after an error |