diff --git a/lapi.c b/lapi.c index 7980ead0..fffd7d26 100644 --- a/lapi.c +++ b/lapi.c @@ -587,6 +587,8 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { ret = luaO_pushvfstring(L, fmt, argp); va_end(argp); luaC_checkGC(L); + if (ret == NULL) /* error? */ + luaD_throw(L, LUA_ERRMEM); lua_unlock(L); return ret; } diff --git a/lauxlib.c b/lauxlib.c index defd4d57..a36655f2 100644 --- a/lauxlib.c +++ b/lauxlib.c @@ -225,7 +225,7 @@ LUALIB_API void luaL_where (lua_State *L, int level) { /* ** Again, the use of 'lua_pushvfstring' ensures this function does ** not need reserved stack space when called. (At worst, it generates -** an error with "stack overflow" instead of the given message.) +** a memory error instead of the given message.) */ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { va_list argp; diff --git a/ldebug.c b/ldebug.c index 9e341f11..d1b47c56 100644 --- a/ldebug.c +++ b/ldebug.c @@ -847,7 +847,8 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { va_start(argp, fmt); msg = luaO_pushvfstring(L, fmt, argp); /* format message */ va_end(argp); - if (isLua(ci)) { /* if Lua function, add source:line information */ + if (msg != NULL && isLua(ci)) { /* Lua function? (and no error) */ + /* add source:line information */ luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci)); setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */ L->top.p--; diff --git a/lobject.c b/lobject.c index 0116e01b..ba10189d 100644 --- a/lobject.c +++ b/lobject.c @@ -480,7 +480,7 @@ void luaO_tostring (lua_State *L, TValue *obj) { #define BUFVFS cast_uint(LUA_IDSIZE + MAXNUMBER2STR + 95) /* -** Buffer used by 'luaO_pushvfstring'. 'err' signals any error while +** Buffer used by 'luaO_pushvfstring'. 'err' signals an error while ** building result (memory error [1] or buffer overflow [2]). */ typedef struct BuffFS { @@ -512,9 +512,14 @@ static void pushbuff (lua_State *L, void *ud) { case 1: luaD_throw(L, LUA_ERRMEM); break; - case 2: - luaG_runerror(L, "buffer overflow"); - break; + case 2: /* length overflow: Add "..." at the end of result */ + if (buff->buffsize - buff->blen < 3) + strcpy(buff->b + buff->blen - 3, "..."); /* 'blen' must be > 3 */ + else { /* there is enough space left for the "..." */ + strcpy(buff->b + buff->blen, "..."); + buff->blen += 3; + } + /* FALLTHROUGH */ default: { /* no errors */ TString *ts = luaS_newlstr(L, buff->b, buff->blen); setsvalue2s(L, L->top.p, ts); @@ -527,8 +532,10 @@ static void pushbuff (lua_State *L, void *ud) { static const char *clearbuff (BuffFS *buff) { lua_State *L = buff->L; const char *res; - pushbuff(L, buff); - res = getstr(tsvalue(s2v(L->top.p - 1))); + if (luaD_rawrunprotected(L, pushbuff, buff) != LUA_OK) /* errors? */ + res = NULL; /* error message is on the top of the stack */ + else + res = getstr(tsvalue(s2v(L->top.p - 1))); if (buff->b != buff->space) /* using dynamic buffer? */ luaM_freearray(L, buff->b, buff->buffsize); /* free it */ return res; @@ -536,12 +543,14 @@ static const char *clearbuff (BuffFS *buff) { static void addstr2buff (BuffFS *buff, const char *str, size_t slen) { + size_t left = buff->buffsize - buff->blen; /* space left in the buffer */ if (buff->err) /* do nothing else after an error */ return; - if (slen > buff->buffsize - buff->blen) { - /* new string doesn't fit into current buffer */ + if (slen > left) { /* new string doesn't fit into current buffer? */ if (slen > ((MAX_SIZE/2) - buff->blen)) { /* overflow? */ - buff->err = 2; + memcpy(buff->b + buff->blen, str, left); /* copy what it can */ + buff->blen = buff->buffsize; + buff->err = 2; /* doesn't add anything else */ return; } else { @@ -552,13 +561,13 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) { : luaM_reallocvector(buff->L, buff->b, buff->buffsize, newsize, char); if (newb == NULL) { /* allocation error? */ - buff->err = 1; + buff->err = 1; /* signal a memory error */ return; } - if (buff->b == buff->space) + if (buff->b == buff->space) /* new buffer (not reallocated)? */ memcpy(newb, buff->b, buff->blen); /* copy previous content */ - buff->b = newb; - buff->buffsize = newsize; + buff->b = newb; /* set new (larger) buffer... */ + buff->buffsize = newsize; /* ...and its new size */ } } memcpy(buff->b + buff->blen, str, slen); /* copy new content */ @@ -651,6 +660,8 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { va_start(argp, fmt); msg = luaO_pushvfstring(L, fmt, argp); va_end(argp); + if (msg == NULL) /* error? */ + luaD_throw(L, LUA_ERRMEM); return msg; } diff --git a/manual/manual.of b/manual/manual.of index f0a2ed94..1ac537f7 100644 --- a/manual/manual.of +++ b/manual/manual.of @@ -3974,7 +3974,7 @@ Lua will call @id{falloc} before raising the error. @APIEntry{const char *lua_pushfstring (lua_State *L, const char *fmt, ...);| -@apii{0,1,v} +@apii{0,1,m} Pushes onto the stack a formatted string and returns a pointer to this string @see{constchar}. @@ -3997,9 +3997,6 @@ The conversion specifiers can only be @Char{%c} (inserts an @T{int} as a one-byte character), and @Char{%U} (inserts an @T{unsigned long} as a @x{UTF-8} byte sequence). -This function may raise errors due to memory overflow -or an invalid conversion specifier. - } @APIEntry{void lua_pushglobaltable (lua_State *L);| @@ -4104,10 +4101,14 @@ onto the stack. const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);| -@apii{0,1,v} +@apii{0,1,-} -Equivalent to @Lid{lua_pushfstring}, except that it receives a @id{va_list} -instead of a variable number of arguments. +Equivalent to @Lid{lua_pushfstring}, +except that it receives a @id{va_list} +instead of a variable number of arguments, +and it does not raise errors. +Instead, in case of errors it pushes the error message +and returns @id{NULL}. } @@ -5636,6 +5637,7 @@ It is defined as the following macro: } It @N{returns 0} (@Lid{LUA_OK}) if there are no errors, or 1 in case of errors. +(Except for out-of-memory errors, which are raised.) } @@ -5800,7 +5802,7 @@ The first line in the file is ignored if it starts with a @T{#}. The string @id{mode} works as in the function @Lid{lua_load}. -This function returns the same results as @Lid{lua_load} +This function returns the same results as @Lid{lua_load}, or @Lid{LUA_ERRFILE} for file-related errors. As @Lid{lua_load}, this function only loads the chunk; @@ -9260,7 +9262,7 @@ the script is compiled as a variadic function. In interactive mode, Lua repeatedly prompts and waits for a line. After reading a line, -Lua first try to interpret the line as an expression. +Lua first tries to interpret the line as an expression. If it succeeds, it prints its value. Otherwise, it interprets the line as a chunk. If you write an incomplete chunk, @@ -9424,6 +9426,11 @@ instead, there is a new option @Lid{LUA_GCPARAM} to that end. Moreover, there were some changes in the parameters themselves. } +@item{ +The function @Lid{lua_pushvfstring} now reports errors, +instead of raising them. +} + } }