diff options
| author | Roberto I <roberto@inf.puc-rio.br> | 2025-08-27 10:30:54 -0300 |
|---|---|---|
| committer | Roberto I <roberto@inf.puc-rio.br> | 2025-08-27 10:30:54 -0300 |
| commit | f87416f1a3e47aa69ed8d27e7406ec6b7848da9a (patch) | |
| tree | 223c07bf1f2c39ca692f74015b52b8670eb6ad52 | |
| parent | 03a3473687ef0df86fc6d31de7d46158a0436666 (diff) | |
| download | lua-f87416f1a3e47aa69ed8d27e7406ec6b7848da9a.tar.gz lua-f87416f1a3e47aa69ed8d27e7406ec6b7848da9a.tar.bz2 lua-f87416f1a3e47aa69ed8d27e7406ec6b7848da9a.zip | |
Added limit to number of elements in a constructor
The reasoning in commit 519c57d5 is wrong: A sequence of nils generates
several fields with just one OP_LOADNIL.
| -rw-r--r-- | lparser.c | 21 | ||||
| -rw-r--r-- | lvm.c | 2 |
2 files changed, 19 insertions, 4 deletions
| @@ -905,6 +905,19 @@ typedef struct ConsControl { | |||
| 905 | } ConsControl; | 905 | } ConsControl; |
| 906 | 906 | ||
| 907 | 907 | ||
| 908 | /* | ||
| 909 | ** Maximum number of elements in a constructor, to control the following: | ||
| 910 | ** * counter overflows; | ||
| 911 | ** * overflows in 'extra' for OP_NEWTABLE and OP_SETLIST; | ||
| 912 | ** * overflows when adding multiple returns in OP_SETLIST. | ||
| 913 | */ | ||
| 914 | #define MAX_CNST (INT_MAX/2) | ||
| 915 | #if MAX_CNST/(MAXARG_vC + 1) > MAXARG_Ax | ||
| 916 | #undef MAX_CNST | ||
| 917 | #define MAX_CNST (MAXARG_Ax * (MAXARG_vC + 1)) | ||
| 918 | #endif | ||
| 919 | |||
| 920 | |||
| 908 | static void recfield (LexState *ls, ConsControl *cc) { | 921 | static void recfield (LexState *ls, ConsControl *cc) { |
| 909 | /* recfield -> (NAME | '['exp']') = exp */ | 922 | /* recfield -> (NAME | '['exp']') = exp */ |
| 910 | FuncState *fs = ls->fs; | 923 | FuncState *fs = ls->fs; |
| @@ -925,7 +938,7 @@ static void recfield (LexState *ls, ConsControl *cc) { | |||
| 925 | 938 | ||
| 926 | 939 | ||
| 927 | static void closelistfield (FuncState *fs, ConsControl *cc) { | 940 | static void closelistfield (FuncState *fs, ConsControl *cc) { |
| 928 | if (cc->v.k == VVOID) return; /* there is no list item */ | 941 | lua_assert(cc->tostore > 0); |
| 929 | luaK_exp2nextreg(fs, &cc->v); | 942 | luaK_exp2nextreg(fs, &cc->v); |
| 930 | cc->v.k = VVOID; | 943 | cc->v.k = VVOID; |
| 931 | if (cc->tostore >= cc->maxtostore) { | 944 | if (cc->tostore >= cc->maxtostore) { |
| @@ -1013,10 +1026,12 @@ static void constructor (LexState *ls, expdesc *t) { | |||
| 1013 | checknext(ls, '{' /*}*/); | 1026 | checknext(ls, '{' /*}*/); |
| 1014 | cc.maxtostore = maxtostore(fs); | 1027 | cc.maxtostore = maxtostore(fs); |
| 1015 | do { | 1028 | do { |
| 1016 | lua_assert(cc.v.k == VVOID || cc.tostore > 0); | ||
| 1017 | if (ls->t.token == /*{*/ '}') break; | 1029 | if (ls->t.token == /*{*/ '}') break; |
| 1018 | closelistfield(fs, &cc); | 1030 | if (cc.v.k != VVOID) /* is there a previous list item? */ |
| 1031 | closelistfield(fs, &cc); /* close it */ | ||
| 1019 | field(ls, &cc); | 1032 | field(ls, &cc); |
| 1033 | luaY_checklimit(fs, cc.tostore + cc.na + cc.nh, MAX_CNST, | ||
| 1034 | "items in a constructor"); | ||
| 1020 | } while (testnext(ls, ',') || testnext(ls, ';')); | 1035 | } while (testnext(ls, ',') || testnext(ls, ';')); |
| 1021 | check_match(ls, /*{*/ '}', '{' /*}*/, line); | 1036 | check_match(ls, /*{*/ '}', '{' /*}*/, line); |
| 1022 | lastlistfield(fs, &cc); | 1037 | lastlistfield(fs, &cc); |
| @@ -1888,7 +1888,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1888 | vmcase(OP_SETLIST) { | 1888 | vmcase(OP_SETLIST) { |
| 1889 | StkId ra = RA(i); | 1889 | StkId ra = RA(i); |
| 1890 | unsigned n = cast_uint(GETARG_vB(i)); | 1890 | unsigned n = cast_uint(GETARG_vB(i)); |
| 1891 | unsigned int last = cast_uint(GETARG_vC(i)); | 1891 | unsigned last = cast_uint(GETARG_vC(i)); |
| 1892 | Table *h = hvalue(s2v(ra)); | 1892 | Table *h = hvalue(s2v(ra)); |
| 1893 | if (n == 0) | 1893 | if (n == 0) |
| 1894 | n = cast_uint(L->top.p - ra) - 1; /* get up to the top */ | 1894 | n = cast_uint(L->top.p - ra) - 1; /* get up to the top */ |
