[BUG] uservalue has an incorrect value In lua 5.4(work2)

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

[BUG] uservalue has an incorrect value In lua 5.4(work2)

actboy168@gmail.com
This is an example that can be reproduced.

for i = 1, 1000 do
    -- lpeg.re
    require 're'
    package.loaded['re'] = nil
    print('test', i)
end

And in lprefix.h add

#include <assert.h>
#define lua_assert(cond) assert(cond)

lpeg is not required, this is just a way to easily create a lot of userdata.

It doesn't reproduce every time, you can try it a few more times.

--actboy168

Reply | Threaded
Open this post in threaded view
|

Re: [BUG] uservalue has an incorrect value In lua 5.4(work2)

Andrew Gierth
>>>>> "actboy168" == actboy168  <[hidden email]> writes:

 actboy168> This is an example that can be reproduced.
 actboy168> for i = 1, 1000 do
 actboy168>     -- lpeg.re
 actboy168>     require 're'
 actboy168>     package.loaded['re'] = nil
 actboy168>     print('test', i)
 actboy168> end

Doesn't need the loop; just doing  require 're'; collectgarbage();
triggers it for me.

--
Andrew.

Reply | Threaded
Open this post in threaded view
|

Re: [BUG] uservalue has an incorrect value In lua 5.4(work2)

Andrew Gierth
>>>>> "Andrew" == Andrew Gierth <[hidden email]> writes:

 Andrew> Doesn't need the loop; just doing require 're';
 Andrew> collectgarbage(); triggers it for me.

So it looks like a bug in generational GC.

What I've found so far is that the states of the "marked" flags of
object U (the userdata) and T (the table stored in the uservalue)
change like this, starting from the creation of T:

T: luaC_newobj: (undef) -> 00010000 (WHITE1 | G_NEW)
T: luaH_getn: 00010000 (WHITE1 | G_NEW) -> 10010000 (RAS | WHITE1 | G_NEW)
U: luaC_barrierback_: 01100100 (FINALIZED | BLACK | G_OLD) -> 01000100 (FINALIZED | G_OLD)
U: luaC_barrierback_: 01000100 (FINALIZED | G_OLD) -> 01000101 (FINALIZED | G_TOUCHED1)
U: propagatemark: 01000101 (FINALIZED | G_TOUCHED1) -> 01100101 (FINALIZED | BLACK | G_TOUCHED1)
T: reallymarkobject: 10010000 (RAS | WHITE1 | G_NEW) -> 10000000 (RAS | G_NEW)
T: propagatemark: 10000000 (RAS | G_NEW) -> 10100000 (RAS | BLACK | G_NEW)
T: traversestrongtable: 10100000 (RAS | BLACK | G_NEW) -> 10000000 (RAS | G_NEW)
T: sweepgen: 10000000 (RAS | G_NEW) -> 10001000 (RAS | WHITE0 | G_NEW)
T: sweepgen: 10001000 (RAS | WHITE0 | G_NEW) -> 10001001 (RAS | WHITE0 | G_SURVIVAL)

and at this point, U (marked black) points at T (marked white), and T
gets freed shortly after without any further changes to either object's
"marked" field.

So unless I'm missing something, the problem here is that the userdata
and its uservalue entries are being treated differently than a strong
table would have been: the strong table is marked grayagain after
traversing if gckind == KGC_GEN, but the userdata remains black after
traversing its uservalue entries. Surely the logic should be the same
for both cases, since both are strong references?

--
Andrew.

Reply | Threaded
Open this post in threaded view
|

Re: [BUG] uservalue has an incorrect value In lua 5.4(work2)

Roberto Ierusalimschy
>  Andrew> Doesn't need the loop; just doing require 're';
>  Andrew> collectgarbage(); triggers it for me.
>
> So it looks like a bug in generational GC.
>
> What I've found so far is that the states of the "marked" flags of
> object U (the userdata) and T (the table stored in the uservalue)
> change like this, starting from the creation of T:
>
> [...]
>
> So unless I'm missing something, the problem here is that the userdata
> and its uservalue entries are being treated differently than a strong
> table would have been: the strong table is marked grayagain after
> traversing if gckind == KGC_GEN, but the userdata remains black after
> traversing its uservalue entries. Surely the logic should be the same
> for both cases, since both are strong references?

Many thanks for the detailed analysis. Great help!

-- Roberto