diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-08-31 13:14:41 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-08-31 13:14:41 -0300 |
commit | 029d269f4d1afd0e9ea0f889eb3e65a7f0fab0f9 (patch) | |
tree | 3a036d990b69013a83df795117b3583abbacfb96 | |
parent | ac65bab25f1eaaf70e1826a6937a74b3a55b521b (diff) | |
download | lua-029d269f4d1afd0e9ea0f889eb3e65a7f0fab0f9.tar.gz lua-029d269f4d1afd0e9ea0f889eb3e65a7f0fab0f9.tar.bz2 lua-029d269f4d1afd0e9ea0f889eb3e65a7f0fab0f9.zip |
bug: dead keys with nil values can stay in weak tables
-rw-r--r-- | bugs | 38 | ||||
-rw-r--r-- | lgc.c | 21 |
2 files changed, 47 insertions, 12 deletions
@@ -3680,9 +3680,9 @@ It needs an "interceptor" 'memcmp' function that continues | |||
3680 | reading memory after a difference is found.]], | 3680 | reading memory after a difference is found.]], |
3681 | patch = [[ | 3681 | patch = [[ |
3682 | 2c2 | 3682 | 2c2 |
3683 | < ** $Id: bugs,v 1.155 2017/07/27 13:55:38 roberto Exp roberto $ | 3683 | < ** $Id: bugs,v 1.156 2017/08/12 13:12:42 roberto Exp roberto $ |
3684 | --- | 3684 | --- |
3685 | > ** $Id: bugs,v 1.155 2017/07/27 13:55:38 roberto Exp roberto $ | 3685 | > ** $Id: bugs,v 1.156 2017/08/12 13:12:42 roberto Exp roberto $ |
3686 | 263c263,264 | 3686 | 263c263,264 |
3687 | < for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) { | 3687 | < for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) { |
3688 | --- | 3688 | --- |
@@ -3837,6 +3837,40 @@ patch = [[ | |||
3837 | } | 3837 | } |
3838 | 3838 | ||
3839 | 3839 | ||
3840 | Bug{ | ||
3841 | what = [[dead keys with nil values can stay in weak tables]], | ||
3842 | report = [[云风 Cloud Wu, 2017/08/15]], | ||
3843 | since = [[5.2]], | ||
3844 | fix = nil, | ||
3845 | example = [[ | ||
3846 | -- The following chunk, under a memory checker like valgrind, | ||
3847 | -- produces a memory access violation. | ||
3848 | |||
3849 | local a = setmetatable({}, {__mode = 'kv'}) | ||
3850 | |||
3851 | a['ABCDEFGHIJKLMNOPQRSTUVWXYZ' .. 'abcdefghijklmnopqrstuvwxyz'] = {} | ||
3852 | a[next(a)] = nil | ||
3853 | collectgarbage() | ||
3854 | print(a['BCDEFGHIJKLMNOPQRSTUVWXYZ' .. 'abcdefghijklmnopqrstuvwxyz']) | ||
3855 | ]], | ||
3856 | patch = [[ | ||
3857 | --- lgc.c 2016/12/22 13:08:50 2.215 | ||
3858 | +++ lgc.c 2017/08/31 16:08:23 | ||
3859 | @@ -643,8 +643,9 @@ | ||
3860 | for (n = gnode(h, 0); n < limit; n++) { | ||
3861 | if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { | ||
3862 | setnilvalue(gval(n)); /* remove value ... */ | ||
3863 | - removeentry(n); /* and remove entry from table */ | ||
3864 | } | ||
3865 | + if (ttisnil(gval(n))) /* is entry empty? */ | ||
3866 | + removeentry(n); /* remove entry from table */ | ||
3867 | } | ||
3868 | } | ||
3869 | } | ||
3870 | ]] | ||
3871 | } | ||
3872 | |||
3873 | |||
3840 | 3874 | ||
3841 | 3875 | ||
3842 | --[=[ | 3876 | --[=[ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.232 2017/06/12 14:21:44 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.233 2017/06/29 15:06:44 roberto Exp roberto $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -117,7 +117,8 @@ static lu_mem atomic (lua_State *L); | |||
117 | 117 | ||
118 | 118 | ||
119 | /* | 119 | /* |
120 | ** If key is not marked, mark its entry as dead. This allows the | 120 | ** Clear keys for empty entries in tables. If entry is empty |
121 | ** and its key is not marked, mark its entry as dead. This allows the | ||
121 | ** collection of the key, but keeps its entry in the table (its removal | 122 | ** collection of the key, but keeps its entry in the table (its removal |
122 | ** could break a chain). Other places never manipulate dead keys, | 123 | ** could break a chain). Other places never manipulate dead keys, |
123 | ** because its associated nil value is enough to signal that the entry | 124 | ** because its associated nil value is enough to signal that the entry |
@@ -688,10 +689,10 @@ static void clearkeys (global_State *g, GCObject *l) { | |||
688 | Table *h = gco2t(l); | 689 | Table *h = gco2t(l); |
689 | Node *n, *limit = gnodelast(h); | 690 | Node *n, *limit = gnodelast(h); |
690 | for (n = gnode(h, 0); n < limit; n++) { | 691 | for (n = gnode(h, 0); n < limit; n++) { |
691 | if (!ttisnil(gval(n)) && (iscleared(g, gckeyN(n)))) { | 692 | if (!ttisnil(gval(n)) && (iscleared(g, gckeyN(n)))) /* unmarked key? */ |
692 | setnilvalue(gval(n)); /* remove value ... */ | 693 | setnilvalue(gval(n)); /* clear value */ |
693 | removeentry(n); /* and remove entry from table */ | 694 | if (ttisnil(gval(n))) /* is entry empty? */ |
694 | } | 695 | removeentry(n); /* remove it from table */ |
695 | } | 696 | } |
696 | } | 697 | } |
697 | } | 698 | } |
@@ -712,10 +713,10 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { | |||
712 | setnilvalue(o); /* remove value */ | 713 | setnilvalue(o); /* remove value */ |
713 | } | 714 | } |
714 | for (n = gnode(h, 0); n < limit; n++) { | 715 | for (n = gnode(h, 0); n < limit; n++) { |
715 | if (iscleared(g, gcvalueN(gval(n)))) { | 716 | if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ |
716 | setnilvalue(gval(n)); /* remove value ... */ | 717 | setnilvalue(gval(n)); /* clear value */ |
717 | removeentry(n); /* and remove entry from table */ | 718 | if (ttisnil(gval(n))) /* is entry empty? */ |
718 | } | 719 | removeentry(n); /* remove it from table */ |
719 | } | 720 | } |
720 | } | 721 | } |
721 | } | 722 | } |