From 4af03c5ae10cfae115069dc5de8ec13b771df749 Mon Sep 17 00:00:00 2001
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Sat, 4 Jul 2015 13:35:14 -0300
Subject: better treatment for integer overflows + all errors throw an error
 (instead of returning nil)

---
 loslib.c | 60 +++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 37 insertions(+), 23 deletions(-)

diff --git a/loslib.c b/loslib.c
index bf436b81..eb444bb2 100644
--- a/loslib.c
+++ b/loslib.c
@@ -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
 ** See Copyright Notice in lua.h
 */
@@ -54,7 +54,12 @@
 */
 #define l_timet			lua_Integer
 #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				/* } */
 
@@ -198,17 +203,29 @@ static int getboolfield (lua_State *L, const char *key) {
 }
 
 
-static int getfield (lua_State *L, const char *key, int d) {
-  int res, isnum;
-  lua_getfield(L, -1, key);
-  res = (int)lua_tointegerx(L, -1, &isnum);
-  if (!isnum) {
-    if (d < 0)
+/* maximum value for date fields (to avoid arithmetic overflows with 'int') */
+#if !defined(L_MAXDATEFIELD)
+#define L_MAXDATEFIELD	(INT_MAX / 2)
+#endif
+
+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);
     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);
-  return res;
+  return (int)res;
 }
 
 
@@ -247,8 +264,8 @@ static int os_date (lua_State *L) {
   else
     stm = l_localtime(&t, &tmr);
   if (stm == NULL)  /* invalid date? */
-    lua_pushnil(L);
-  else if (strcmp(s, "*t") == 0) {
+    luaL_error(L, "time result cannot be represented in this installation");
+  if (strcmp(s, "*t") == 0) {
     lua_createtable(L, 0, 9);  /* 9 = number of fields */
     setfield(L, "sec", stm->tm_sec);
     setfield(L, "min", stm->tm_min);
@@ -290,21 +307,18 @@ static int os_time (lua_State *L) {
     struct tm ts;
     luaL_checktype(L, 1, LUA_TTABLE);
     lua_settop(L, 1);  /* make sure table is at the top */
-    ts.tm_sec = getfield(L, "sec", 0);
-    ts.tm_min = getfield(L, "min", 0);
-    ts.tm_hour = getfield(L, "hour", 12);
-    ts.tm_mday = getfield(L, "day", -1);
-    ts.tm_mon = getfield(L, "month", -1) - 1;
-    ts.tm_year = getfield(L, "year", -1) - 1900;
+    ts.tm_sec = getfield(L, "sec", 0, 0);
+    ts.tm_min = getfield(L, "min", 0, 0);
+    ts.tm_hour = getfield(L, "hour", 12, 0);
+    ts.tm_mday = getfield(L, "day", -1, 0);
+    ts.tm_mon = getfield(L, "month", -1, 1);
+    ts.tm_year = getfield(L, "year", -1, 1900);
     ts.tm_isdst = getboolfield(L, "isdst");
     t = mktime(&ts);
   }
-  if (t != (time_t)(l_timet)t)
-    luaL_error(L, "time result cannot be represented in this Lua installation");
-  else if (t == (time_t)(-1))
-    lua_pushnil(L);
-  else
-    l_pushtime(L, t);
+  if (t != (time_t)(l_timet)t || t == (time_t)(-1))
+    luaL_error(L, "time result cannot be represented in this installation");
+  l_pushtime(L, t);
   return 1;
 }
 
-- 
cgit v1.2.3-55-g6feb