diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-11-03 16:34:36 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-11-03 16:34:36 -0300 |
| commit | 58216600eba27d472de33dbb89e2f3e629bf8a59 (patch) | |
| tree | 9504237097bb72548e5e7b66b753dc23056330a8 | |
| parent | 94cbe4651156a84dd9114d7daaa61acd050adbe0 (diff) | |
| download | lua-58216600eba27d472de33dbb89e2f3e629bf8a59.tar.gz lua-58216600eba27d472de33dbb89e2f3e629bf8a59.tar.bz2 lua-58216600eba27d472de33dbb89e2f3e629bf8a59.zip | |
'luaL_newstate' should not allocate extra memory
The allocation of a userdata for the state of the warn system can
cause a panic if it fails; 'luaL_ref' also can fail. This commit
re-implements the warn system so that it does not need an explicit
state. Instead, the system uses different functions to represent
the different states.
| -rw-r--r-- | lauxlib.c | 72 | ||||
| -rw-r--r-- | lobject.c | 2 | ||||
| -rw-r--r-- | ltests.c | 2 |
3 files changed, 50 insertions, 26 deletions
| @@ -283,10 +283,10 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { | |||
| 283 | 283 | ||
| 284 | 284 | ||
| 285 | LUALIB_API int luaL_execresult (lua_State *L, int stat) { | 285 | LUALIB_API int luaL_execresult (lua_State *L, int stat) { |
| 286 | const char *what = "exit"; /* type of termination */ | ||
| 287 | if (stat != 0 && errno != 0) /* error with an 'errno'? */ | 286 | if (stat != 0 && errno != 0) /* error with an 'errno'? */ |
| 288 | return luaL_fileresult(L, 0, NULL); | 287 | return luaL_fileresult(L, 0, NULL); |
| 289 | else { | 288 | else { |
| 289 | const char *what = "exit"; /* type of termination */ | ||
| 290 | l_inspectstat(stat, what); /* interpret result */ | 290 | l_inspectstat(stat, what); /* interpret result */ |
| 291 | if (*what == 'e' && stat == 0) /* successful termination? */ | 291 | if (*what == 'e' && stat == 0) /* successful termination? */ |
| 292 | lua_pushboolean(L, 1); | 292 | lua_pushboolean(L, 1); |
| @@ -1006,43 +1006,67 @@ static int panic (lua_State *L) { | |||
| 1006 | 1006 | ||
| 1007 | 1007 | ||
| 1008 | /* | 1008 | /* |
| 1009 | ** Emit a warning. '*warnstate' means: | 1009 | ** Warning functions: |
| 1010 | ** 0 - warning system is off; | 1010 | ** warnfoff: warning system is off |
| 1011 | ** 1 - ready to start a new message; | 1011 | ** warnfon: ready to start a new message |
| 1012 | ** 2 - previous message is to be continued. | 1012 | ** warnfcont: previous message is to be continued |
| 1013 | */ | 1013 | */ |
| 1014 | static void warnf (void *ud, const char *message, int tocont) { | 1014 | static void warnfoff (void *ud, const char *message, int tocont); |
| 1015 | int *warnstate = (int *)ud; | 1015 | static void warnfon (void *ud, const char *message, int tocont); |
| 1016 | if (*warnstate != 2 && !tocont && *message == '@') { /* control message? */ | 1016 | static void warnfcont (void *ud, const char *message, int tocont); |
| 1017 | if (strcmp(message, "@off") == 0) | 1017 | |
| 1018 | *warnstate = 0; | 1018 | |
| 1019 | else if (strcmp(message, "@on") == 0) | 1019 | /* |
| 1020 | *warnstate = 1; | 1020 | ** Check whether message is a control message. If so, execute the |
| 1021 | return; | 1021 | ** control or ignore it if unknown. |
| 1022 | */ | ||
| 1023 | static int checkcontrol (lua_State *L, const char *message, int tocont) { | ||
| 1024 | if (tocont || *(message++) != '@') /* not a control message? */ | ||
| 1025 | return 0; | ||
| 1026 | else { | ||
| 1027 | if (strcmp(message, "off") == 0) | ||
| 1028 | lua_setwarnf(L, warnfoff, L); /* turn warnings off */ | ||
| 1029 | else if (strcmp(message, "on") == 0) | ||
| 1030 | lua_setwarnf(L, warnfon, L); /* turn warnings on */ | ||
| 1031 | return 1; /* it was a control message */ | ||
| 1022 | } | 1032 | } |
| 1023 | else if (*warnstate == 0) /* warnings off? */ | 1033 | } |
| 1024 | return; | 1034 | |
| 1025 | if (*warnstate == 1) /* previous message was the last? */ | 1035 | |
| 1026 | lua_writestringerror("%s", "Lua warning: "); /* start a new warning */ | 1036 | static void warnfoff (void *ud, const char *message, int tocont) { |
| 1037 | checkcontrol((lua_State *)ud, message, tocont); | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | |||
| 1041 | /* | ||
| 1042 | ** Writes the message and handle 'tocont', finishing the message | ||
| 1043 | ** if needed and setting the next warn function. | ||
| 1044 | */ | ||
| 1045 | static void warnfcont (void *ud, const char *message, int tocont) { | ||
| 1046 | lua_State *L = (lua_State *)ud; | ||
| 1027 | lua_writestringerror("%s", message); /* write message */ | 1047 | lua_writestringerror("%s", message); /* write message */ |
| 1028 | if (tocont) /* not the last part? */ | 1048 | if (tocont) /* not the last part? */ |
| 1029 | *warnstate = 2; /* to be continued */ | 1049 | lua_setwarnf(L, warnfcont, L); /* to be continued */ |
| 1030 | else { /* last part */ | 1050 | else { /* last part */ |
| 1031 | lua_writestringerror("%s", "\n"); /* finish message with end-of-line */ | 1051 | lua_writestringerror("%s", "\n"); /* finish message with end-of-line */ |
| 1032 | *warnstate = 1; /* ready to start a new message */ | 1052 | lua_setwarnf(L, warnfon, L); /* next call is a new message */ |
| 1033 | } | 1053 | } |
| 1034 | } | 1054 | } |
| 1035 | 1055 | ||
| 1036 | 1056 | ||
| 1057 | static void warnfon (void *ud, const char *message, int tocont) { | ||
| 1058 | if (checkcontrol((lua_State *)ud, message, tocont)) /* control message? */ | ||
| 1059 | return; /* nothing else to be done */ | ||
| 1060 | lua_writestringerror("%s", "Lua warning: "); /* start a new warning */ | ||
| 1061 | warnfcont(ud, message, tocont); /* finish processing */ | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | |||
| 1037 | LUALIB_API lua_State *luaL_newstate (void) { | 1065 | LUALIB_API lua_State *luaL_newstate (void) { |
| 1038 | lua_State *L = lua_newstate(l_alloc, NULL); | 1066 | lua_State *L = lua_newstate(l_alloc, NULL); |
| 1039 | if (L) { | 1067 | if (L) { |
| 1040 | int *warnstate; /* space for warning state */ | ||
| 1041 | lua_atpanic(L, &panic); | 1068 | lua_atpanic(L, &panic); |
| 1042 | warnstate = (int *)lua_newuserdatauv(L, sizeof(int), 0); | 1069 | lua_setwarnf(L, warnfoff, L); /* default is warnings off */ |
| 1043 | luaL_ref(L, LUA_REGISTRYINDEX); /* make sure it won't be collected */ | ||
| 1044 | *warnstate = 0; /* default is warnings off */ | ||
| 1045 | lua_setwarnf(L, warnf, warnstate); | ||
| 1046 | } | 1070 | } |
| 1047 | return L; | 1071 | return L; |
| 1048 | } | 1072 | } |
| @@ -258,7 +258,7 @@ static const char *l_str2d (const char *s, lua_Number *result) { | |||
| 258 | if (endptr == NULL) { /* failed? may be a different locale */ | 258 | if (endptr == NULL) { /* failed? may be a different locale */ |
| 259 | char buff[L_MAXLENNUM + 1]; | 259 | char buff[L_MAXLENNUM + 1]; |
| 260 | const char *pdot = strchr(s, '.'); | 260 | const char *pdot = strchr(s, '.'); |
| 261 | if (strlen(s) > L_MAXLENNUM || pdot == NULL) | 261 | if (pdot == NULL || strlen(s) > L_MAXLENNUM) |
| 262 | return NULL; /* string too long or no dot; fail */ | 262 | return NULL; /* string too long or no dot; fail */ |
| 263 | strcpy(buff, s); /* copy string to buffer */ | 263 | strcpy(buff, s); /* copy string to buffer */ |
| 264 | buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ | 264 | buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ |
| @@ -863,7 +863,7 @@ static int alloc_failnext (lua_State *L) { | |||
| 863 | l_memcontrol.failnext = 1; | 863 | l_memcontrol.failnext = 1; |
| 864 | return 0; | 864 | return 0; |
| 865 | } | 865 | } |
| 866 | 866 | ||
| 867 | 867 | ||
| 868 | static int settrick (lua_State *L) { | 868 | static int settrick (lua_State *L) { |
| 869 | if (ttisnil(obj_at(L, 1))) | 869 | if (ttisnil(obj_at(L, 1))) |
