better treatment for integer overflows + all errors throw an error

(instead of returning nil)
This commit is contained in:
Roberto Ierusalimschy
2015-07-04 13:35:14 -03:00
parent bde17a419d
commit 4af03c5ae1

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: loslib.c,v 1.56 2015/02/09 17:41:54 roberto Exp roberto $ ** $Id: loslib.c,v 1.57 2015/04/10 17:41:04 roberto Exp roberto $
** Standard Operating System library ** Standard Operating System library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -54,7 +54,12 @@
*/ */
#define l_timet lua_Integer #define l_timet lua_Integer
#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) #define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t))
#define l_checktime(L,a) ((time_t)luaL_checkinteger(L,a))
static time_t l_checktime (lua_State *L, int arg) {
lua_Integer t = luaL_checkinteger(L, arg);
luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
return (time_t)t;
}
#endif /* } */ #endif /* } */
@@ -198,17 +203,29 @@ static int getboolfield (lua_State *L, const char *key) {
} }
static int getfield (lua_State *L, const char *key, int d) { /* maximum value for date fields (to avoid arithmetic overflows with 'int') */
int res, isnum; #if !defined(L_MAXDATEFIELD)
lua_getfield(L, -1, key); #define L_MAXDATEFIELD (INT_MAX / 2)
res = (int)lua_tointegerx(L, -1, &isnum); #endif
if (!isnum) {
if (d < 0) static int getfield (lua_State *L, const char *key, int d, int delta) {
int isnum;
int t = lua_getfield(L, -1, key);
lua_Integer res = lua_tointegerx(L, -1, &isnum);
if (!isnum) { /* field is not a number? */
if (t != LUA_TNIL) /* some other value? */
return luaL_error(L, "field '%s' not an integer", key);
else if (d < 0) /* abssent field; no default? */
return luaL_error(L, "field '%s' missing in date table", key); return luaL_error(L, "field '%s' missing in date table", key);
res = d; res = d;
} }
else {
if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
return luaL_error(L, "field '%s' out-of-bounds", key);
res -= delta;
}
lua_pop(L, 1); lua_pop(L, 1);
return res; return (int)res;
} }
@@ -247,8 +264,8 @@ static int os_date (lua_State *L) {
else else
stm = l_localtime(&t, &tmr); stm = l_localtime(&t, &tmr);
if (stm == NULL) /* invalid date? */ if (stm == NULL) /* invalid date? */
lua_pushnil(L); luaL_error(L, "time result cannot be represented in this installation");
else if (strcmp(s, "*t") == 0) { if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */ lua_createtable(L, 0, 9); /* 9 = number of fields */
setfield(L, "sec", stm->tm_sec); setfield(L, "sec", stm->tm_sec);
setfield(L, "min", stm->tm_min); setfield(L, "min", stm->tm_min);
@@ -290,21 +307,18 @@ static int os_time (lua_State *L) {
struct tm ts; struct tm ts;
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); /* make sure table is at the top */ lua_settop(L, 1); /* make sure table is at the top */
ts.tm_sec = getfield(L, "sec", 0); ts.tm_sec = getfield(L, "sec", 0, 0);
ts.tm_min = getfield(L, "min", 0); ts.tm_min = getfield(L, "min", 0, 0);
ts.tm_hour = getfield(L, "hour", 12); ts.tm_hour = getfield(L, "hour", 12, 0);
ts.tm_mday = getfield(L, "day", -1); ts.tm_mday = getfield(L, "day", -1, 0);
ts.tm_mon = getfield(L, "month", -1) - 1; ts.tm_mon = getfield(L, "month", -1, 1);
ts.tm_year = getfield(L, "year", -1) - 1900; ts.tm_year = getfield(L, "year", -1, 1900);
ts.tm_isdst = getboolfield(L, "isdst"); ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts); t = mktime(&ts);
} }
if (t != (time_t)(l_timet)t) if (t != (time_t)(l_timet)t || t == (time_t)(-1))
luaL_error(L, "time result cannot be represented in this Lua installation"); luaL_error(L, "time result cannot be represented in this installation");
else if (t == (time_t)(-1)) l_pushtime(L, t);
lua_pushnil(L);
else
l_pushtime(L, t);
return 1; return 1;
} }