'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.
This commit is contained in:
Roberto Ierusalimschy
2020-11-03 16:34:36 -03:00
parent 94cbe46511
commit 58216600eb
3 changed files with 50 additions and 26 deletions

View File

@@ -283,10 +283,10 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
LUALIB_API int luaL_execresult (lua_State *L, int stat) { LUALIB_API int luaL_execresult (lua_State *L, int stat) {
const char *what = "exit"; /* type of termination */
if (stat != 0 && errno != 0) /* error with an 'errno'? */ if (stat != 0 && errno != 0) /* error with an 'errno'? */
return luaL_fileresult(L, 0, NULL); return luaL_fileresult(L, 0, NULL);
else { else {
const char *what = "exit"; /* type of termination */
l_inspectstat(stat, what); /* interpret result */ l_inspectstat(stat, what); /* interpret result */
if (*what == 'e' && stat == 0) /* successful termination? */ if (*what == 'e' && stat == 0) /* successful termination? */
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
@@ -1006,43 +1006,67 @@ static int panic (lua_State *L) {
/* /*
** Emit a warning. '*warnstate' means: ** Warning functions:
** 0 - warning system is off; ** warnfoff: warning system is off
** 1 - ready to start a new message; ** warnfon: ready to start a new message
** 2 - previous message is to be continued. ** warnfcont: previous message is to be continued
*/ */
static void warnf (void *ud, const char *message, int tocont) { static void warnfoff (void *ud, const char *message, int tocont);
int *warnstate = (int *)ud; static void warnfon (void *ud, const char *message, int tocont);
if (*warnstate != 2 && !tocont && *message == '@') { /* control message? */ static void warnfcont (void *ud, const char *message, int tocont);
if (strcmp(message, "@off") == 0)
*warnstate = 0;
else if (strcmp(message, "@on") == 0) /*
*warnstate = 1; ** Check whether message is a control message. If so, execute the
return; ** control or ignore it if unknown.
*/
static int checkcontrol (lua_State *L, const char *message, int tocont) {
if (tocont || *(message++) != '@') /* not a control message? */
return 0;
else {
if (strcmp(message, "off") == 0)
lua_setwarnf(L, warnfoff, L); /* turn warnings off */
else if (strcmp(message, "on") == 0)
lua_setwarnf(L, warnfon, L); /* turn warnings on */
return 1; /* it was a control message */
} }
else if (*warnstate == 0) /* warnings off? */ }
return;
if (*warnstate == 1) /* previous message was the last? */
lua_writestringerror("%s", "Lua warning: "); /* start a new warning */ static void warnfoff (void *ud, const char *message, int tocont) {
checkcontrol((lua_State *)ud, message, tocont);
}
/*
** Writes the message and handle 'tocont', finishing the message
** if needed and setting the next warn function.
*/
static void warnfcont (void *ud, const char *message, int tocont) {
lua_State *L = (lua_State *)ud;
lua_writestringerror("%s", message); /* write message */ lua_writestringerror("%s", message); /* write message */
if (tocont) /* not the last part? */ if (tocont) /* not the last part? */
*warnstate = 2; /* to be continued */ lua_setwarnf(L, warnfcont, L); /* to be continued */
else { /* last part */ else { /* last part */
lua_writestringerror("%s", "\n"); /* finish message with end-of-line */ lua_writestringerror("%s", "\n"); /* finish message with end-of-line */
*warnstate = 1; /* ready to start a new message */ lua_setwarnf(L, warnfon, L); /* next call is a new message */
} }
} }
static void warnfon (void *ud, const char *message, int tocont) {
if (checkcontrol((lua_State *)ud, message, tocont)) /* control message? */
return; /* nothing else to be done */
lua_writestringerror("%s", "Lua warning: "); /* start a new warning */
warnfcont(ud, message, tocont); /* finish processing */
}
LUALIB_API lua_State *luaL_newstate (void) { LUALIB_API lua_State *luaL_newstate (void) {
lua_State *L = lua_newstate(l_alloc, NULL); lua_State *L = lua_newstate(l_alloc, NULL);
if (L) { if (L) {
int *warnstate; /* space for warning state */
lua_atpanic(L, &panic); lua_atpanic(L, &panic);
warnstate = (int *)lua_newuserdatauv(L, sizeof(int), 0); lua_setwarnf(L, warnfoff, L); /* default is warnings off */
luaL_ref(L, LUA_REGISTRYINDEX); /* make sure it won't be collected */
*warnstate = 0; /* default is warnings off */
lua_setwarnf(L, warnf, warnstate);
} }
return L; return L;
} }

View File

@@ -258,7 +258,7 @@ static const char *l_str2d (const char *s, lua_Number *result) {
if (endptr == NULL) { /* failed? may be a different locale */ if (endptr == NULL) { /* failed? may be a different locale */
char buff[L_MAXLENNUM + 1]; char buff[L_MAXLENNUM + 1];
const char *pdot = strchr(s, '.'); const char *pdot = strchr(s, '.');
if (strlen(s) > L_MAXLENNUM || pdot == NULL) if (pdot == NULL || strlen(s) > L_MAXLENNUM)
return NULL; /* string too long or no dot; fail */ return NULL; /* string too long or no dot; fail */
strcpy(buff, s); /* copy string to buffer */ strcpy(buff, s); /* copy string to buffer */
buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */

View File

@@ -863,7 +863,7 @@ static int alloc_failnext (lua_State *L) {
l_memcontrol.failnext = 1; l_memcontrol.failnext = 1;
return 0; return 0;
} }
static int settrick (lua_State *L) { static int settrick (lua_State *L) {
if (ttisnil(obj_at(L, 1))) if (ttisnil(obj_at(L, 1)))