]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Further changes to the date/time functions to suppress harmless signed
authordrh <drh@noemail.net>
Wed, 30 Nov 2016 00:48:28 +0000 (00:48 +0000)
committerdrh <drh@noemail.net>
Wed, 30 Nov 2016 00:48:28 +0000 (00:48 +0000)
integer overflow warnings that could have occurred when doing out-of-range
date calculations which, according to the docs, give undefined results.

FossilOrigin-Name: dc453b3403450b1d8cc53daf0721fed025b9053c

manifest
manifest.uuid
src/date.c
test/date.test

index 733c2d390f568b4bbac180e0348a97bf07c2405f..aecf668d2a8a1a1205bb59a37b964035f5e6b0a1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C The\sdocumentation\ssays\sthat\sthe\sbuilt-in\sdate-time\sfunctions\sgive\sundefined\nresults\sfor\sdates\sbefore\s0000-01-01\sand\safter\s9999-12-31.\s\sChange\sthe\nactually\simplementation\sso\sthat\sthe\sanswer\sgiven\sis\sreally\sNULL.\s\sThis\salso\navoids\sunnecessary\shand-wringing\sover\san\ssigned\sinteger\soverflow\sthat\smight\notherwise\soccur\swhen\sprocessing\sout-of-bound\sdates.
-D 2016-11-29T20:39:48.413
+C Further\schanges\sto\sthe\sdate/time\sfunctions\sto\ssuppress\sharmless\ssigned\ninteger\soverflow\swarnings\sthat\scould\shave\soccurred\swhen\sdoing\sout-of-range\ndate\scalculations\swhich,\saccording\sto\sthe\sdocs,\sgive\sundefined\sresults.
+D 2016-11-30T00:48:28.495
 F Makefile.in 6b572807415d3f0a379cebc9461416d8df4a12c8
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc bb4d970894abbbe0e88d00aac29bd52af8bc95f4
@@ -337,7 +337,7 @@ F src/build.c 178f16698cbcb43402c343a9413fe22c99ffee21
 F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c a2a52d6e353f459d8ab0f07321f60fafa47d5421
-F src/date.c 53a4019b90ae1c9cb990196eed0ed196d3f341e1
+F src/date.c 736c1f36c58bb137f64d8d1f72467dc027832563
 F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
 F src/delete.c cac97d1117a3008934da3a6a587b3608e65e1495
 F src/expr.c 8c224aa28278a5c1eed55247b7a571ff388ad5c2
@@ -626,7 +626,7 @@ F test/csv01.test e0ba3caaa57e4c667a0b45977689fb8082f14348
 F test/ctime.test ff6c38e822459d6ca743c34901caf57740b08b54
 F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
 F test/cursorhint2.test fa41f0d997e67db921d08c31e73111b32811201a
-F test/date.test 47e7f7057c0efac0e5e26da2d7b6a9a128139de6
+F test/date.test a6a5a48b90907bca9fbcc79a30be5a715c1ab2fc
 F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
 F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
 F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
@@ -1535,7 +1535,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 9021f6875f897d8b609ebcc04162dc6e0b529a4a
-R e95c6d806c4c5b465cfcf2c97462edc9
+P d410a839752153c6d8be08f758abfbc16475745a
+R 4de84d6de9c4735ca2171beb11da6949
 U drh
-Z f7a67f418429ef937fb437b96080796e
+Z a5d0c3a9dbd00d301630dafcf90b9504
index 95eeb46ae61c430a6fc2377f6a72ffeb24013f2a..f5cb5e6a0de37d20fc924a5df870fff262b00df2 100644 (file)
@@ -1 +1 @@
-d410a839752153c6d8be08f758abfbc16475745a
\ No newline at end of file
+dc453b3403450b1d8cc53daf0721fed025b9053c
\ No newline at end of file
index a90b5318b8d3b5b4b026390e72eb3b6bf20c998a..6a6743f86d3ce97d239f1c66cd90db0c7e66a542 100644 (file)
@@ -65,17 +65,17 @@ struct tm *__cdecl localtime(const time_t *);
 */
 typedef struct DateTime DateTime;
 struct DateTime {
-  sqlite3_int64 iJD; /* The julian day number times 86400000 */
-  int Y, M, D;       /* Year, month, and day */
-  int h, m;          /* Hour and minutes */
-  int tz;            /* Timezone offset in minutes */
-  double s;          /* Seconds */
-  char validYMD;     /* True (1) if Y,M,D are valid */
-  char validHMS;     /* True (1) if h,m,s are valid */
-  char validJD;      /* True (1) if iJD is valid */
-  char validTZ;      /* True (1) if tz is valid */
-  char tzSet;        /* Timezone was set explicitly */
-  char isError;      /* An overflow has occurred */
+  sqlite3_uint64 iJD; /* The julian day number times 86400000 */
+  int Y, M, D;        /* Year, month, and day */
+  int h, m;           /* Hour and minutes */
+  int tz;             /* Timezone offset in minutes */
+  double s;           /* Seconds */
+  char validYMD;      /* True (1) if Y,M,D are valid */
+  char validHMS;      /* True (1) if h,m,s are valid */
+  char validJD;       /* True (1) if iJD is valid */
+  char validTZ;       /* True (1) if tz is valid */
+  char tzSet;         /* Timezone was set explicitly */
+  char isError;       /* An overflow has occurred */
 };
 
 
@@ -232,6 +232,14 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
   return 0;
 }
 
+/*
+** Put the DateTime object into its error state.
+*/
+static void datetimeError(DateTime *p){
+  memset(p, 0, sizeof(*p));
+  p->isError = 1;
+}
+
 /*
 ** Convert from YYYY-MM-DD HH:MM:SS to julian day.  We always assume
 ** that the YYYY-MM-DD is according to the Gregorian calendar.
@@ -251,6 +259,10 @@ static void computeJD(DateTime *p){
     M = 1;
     D = 1;
   }
+  if( Y<-4713 || Y>9999 ){
+    datetimeError(p);
+    return;
+  }
   if( M<=2 ){
     Y--;
     M += 12;
@@ -373,7 +385,7 @@ static int parseDateOrTime(
 ** The input is the JulianDay times 86400000.
 */
 static int validJulianDay(sqlite3_int64 iJD){
-  return iJD>=148699540800000 && iJD<=464269060799999;
+  return iJD>=0 && iJD<=464269060799999;
 }
 
 /*
@@ -387,8 +399,7 @@ static void computeYMD(DateTime *p){
     p->M = 1;
     p->D = 1;
   }else if( !validJulianDay(p->iJD) ){
-    memset(p, 0, sizeof(*p));
-    p->isError = 1;
+    datetimeError(p);
     return;
   }else{
     Z = (int)((p->iJD + 43200000)/86400000);
@@ -713,6 +724,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
     case '8':
     case '9': {
       double rRounder;
+      double rAbs;
       for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
       if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
         rc = 1;
@@ -749,15 +761,16 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
       computeJD(p);
       rc = 0;
       rRounder = r<0 ? -0.5 : +0.5;
-      if( n==3 && strcmp(z,"day")==0 ){
+      rAbs = r<0 ? -r : r;
+      if( n==3 && strcmp(z,"day")==0 && rAbs<5373485.0 ){
         p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder);
-      }else if( n==4 && strcmp(z,"hour")==0 ){
+      }else if( n==4 && strcmp(z,"hour")==0 && rAbs<128963628.0 ){
         p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder);
-      }else if( n==6 && strcmp(z,"minute")==0 ){
+      }else if( n==6 && strcmp(z,"minute")==0 && rAbs<7737817680.0 ){
         p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder);
-      }else if( n==6 && strcmp(z,"second")==0 ){
+      }else if( n==6 && strcmp(z,"second")==0 && rAbs<464269060800.0 ){
         p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder);
-      }else if( n==5 && strcmp(z,"month")==0 ){
+      }else if( n==5 && strcmp(z,"month")==0 && rAbs<176546.0 ){
         int x, y;
         computeYMD_HMS(p);
         p->M += (int)r;
@@ -770,7 +783,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
         if( y!=r ){
           p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder);
         }
-      }else if( n==4 && strcmp(z,"year")==0 ){
+      }else if( n==4 && strcmp(z,"year")==0 && rAbs<14713.0 ){
         int y = (int)r;
         computeYMD_HMS(p);
         p->Y += y;
index 0286bcc3bca0c32e416e954addcaea4cfe534bac..2d336e6c007dd934c49bc2e97f518d1f50133ead 100644 (file)
@@ -61,7 +61,7 @@ datetest 1.19 {julianday('2000-01-01 12:00:00.1')}   2451545.00000116
 datetest 1.20 {julianday('2000-01-01 12:00:00.01')}  2451545.00000012
 datetest 1.21 {julianday('2000-01-01 12:00:00.001')} 2451545.00000001
 datetest 1.22 {julianday('2000-01-01 12:00:00.')} NULL
-datetest 1.23 julianday(12345.6) NULL
+datetest 1.23 julianday(12345.6) 12345.6
 datetest 1.23b julianday(1721059.5) 1721059.5
 datetest 1.24 {julianday('2001-01-01 12:00:00 bogus')} NULL
 datetest 1.25 {julianday('2001-01-01 bogus')} NULL
@@ -418,6 +418,16 @@ datetest 8.19 {datetime('now','11.25 seconds')} {2003-10-22 12:34:11}
 datetest 8.90 {datetime('now','abcdefghijklmnopqrstuvwyxzABCDEFGHIJLMNOP')} NULL
 set sqlite_current_time 0
 
+# Negative years work.  Example:  '-4713-11-26' is JD 1.5.
+#
+datetest 9.1 {julianday('-4713-11-24 12:00:00')} {0.0}
+datetest 9.2 {julianday(datetime(5))} {5.0}
+datetest 9.3 {julianday(datetime(10))} {10.0}
+datetest 9.4 {julianday(datetime(100))} {100.0}
+datetest 9.5 {julianday(datetime(1000))} {1000.0}
+datetest 9.6 {julianday(datetime(10000))} {10000.0}
+datetest 9.7 {julianday(datetime(100000))} {100000.0}
+
 # datetime() with just an HH:MM:SS correctly inserts the date 2000-01-01.
 #
 datetest 10.1 {datetime('01:02:03')}  {2000-01-01 01:02:03}
@@ -550,4 +560,41 @@ do_test date-15.2 {
   }
 } {1}
 
+# Tests of extreme values in date/time functions.  Run with UBSan or the
+# equivalent to verify no signed interger overflow warnings.
+#
+datetest 16.1 {date(147483649)} NULL
+datetest 16.2 {datetime(0)} {-4713-11-24 12:00:00}
+datetest 16.3 {datetime(5373484.49999999)} {9999-12-31 23:59:59}
+datetest 16.4 {julianday('-4713-11-24 12:00:00')} 0.0
+datetest 16.5 {julianday('9999-12-31 23:59:59.999')} 5373484.49999999
+datetest 16.6 {datetime(0,'+464269060799 seconds')} {9999-12-31 23:59:59}
+datetest 16.7 {datetime(0,'+464269060800 seconds')} NULL
+datetest 16.8 {datetime(0,'+7737817679 minutes')} {9999-12-31 23:59:00}
+datetest 16.9 {datetime(0,'+7737817680 minutes')} NULL
+datetest 16.10 {datetime(0,'+128963627 hours')} {9999-12-31 23:00:00}
+datetest 16.11 {datetime(0,'+128963628 hours')} NULL
+datetest 16.12 {datetime(0,'+5373484 days')} {9999-12-31 12:00:00}
+datetest 16.13 {datetime(0,'+5373485 days')} NULL
+datetest 16.14 {datetime(0,'+176545 months')} {9999-12-24 12:00:00}
+datetest 16.15 {datetime(0,'+176546 months')} NULL
+datetest 16.16 {datetime(0,'+14712 years')} {9999-11-24 12:00:00}
+datetest 16.17 {datetime(0,'+14713 years')} NULL
+datetest 16.20 {datetime(5373484.4999999,'-464269060799 seconds')} \
+                {-4713-11-24 12:00:00}
+datetest 16.21 {datetime(5373484,'-464269060800 seconds')} NULL
+datetest 16.22 {datetime(5373484.4999999,'-7737817679 minutes')} \
+               {-4713-11-24 12:00:59}
+datetest 16.23 {datetime(5373484,'-7737817680 minutes')} NULL
+datetest 16.24 {datetime(5373484.4999999,'-128963627 hours')} \
+               {-4713-11-24 12:59:59}
+datetest 16.25 {datetime(5373484,'-128963628 hours')} NULL
+datetest 16.26 {datetime(5373484,'-5373484 days')} {-4713-11-24 12:00:00}
+datetest 16.27 {datetime(5373484,'-5373485 days')} NULL
+datetest 16.28 {datetime(5373484,'-176545 months')} {-4713-12-01 12:00:00}
+datetest 16.29 {datetime(5373484,'-176546 months')} NULL
+datetest 16.30 {datetime(5373484,'-14712 years')} {-4713-12-31 12:00:00}
+datetest 16.31 {datetime(5373484,'-14713 years')} NULL
+
+
 finish_test