/ Check-in [76ae8257]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Return an error if localtime_r() fails within one of the date/time functions. Fix for [bd484a090c].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:76ae8257efc1df6e20ce5718d4824adbbde423ec
User & Date: dan 2011-06-21 12:47:30
Context
2011-06-21
12:53
Fix an error made in the previous commit. The parameters to localtime_s() were accidentally reversed. Ticket [bd484a090c807]. check-in: 97e86ec6 user: dan tags: trunk
12:47
Return an error if localtime_r() fails within one of the date/time functions. Fix for [bd484a090c]. check-in: 76ae8257 user: dan tags: trunk
03:36
Add a new AWK script in the tool/ folder for converting text files into C string literals. Use it for building sqlite3_analyzer. check-in: dcb46d3f user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/date.c.

   408    408   static void clearYMD_HMS_TZ(DateTime *p){
   409    409     p->validYMD = 0;
   410    410     p->validHMS = 0;
   411    411     p->validTZ = 0;
   412    412   }
   413    413   
   414    414   #ifndef SQLITE_OMIT_LOCALTIME
          415  +
   415    416   /*
   416         -** Compute the difference (in milliseconds)
   417         -** between localtime and UTC (a.k.a. GMT)
   418         -** for the time value p where p is in UTC.
          417  +** The following three functions - osLocaltime_r(), osLocaltime_s() and
          418  +** osLocaltime() - are wrappers around system functions localtime_r(),
          419  +** localtime_s() and localtime(), respectively.
          420  +**
          421  +** If the sqlite3GlobalConfig.bLocaltimeFault variable is true when one
          422  +** of the following wrappers is called, it returns an error.
   419    423   */
   420         -static sqlite3_int64 localtimeOffset(DateTime *p){
          424  +#ifndef SQLITE_OMIT_BUILTIN_TEST
          425  +
          426  +#ifdef HAVE_LOCALTIME_R
          427  +static struct tm * osLocaltime_r(time_t *t, struct tm *pTm){
          428  +  if( sqlite3GlobalConfig.bLocaltimeFault ) return 0;
          429  +  return localtime_r(t);
          430  +}
          431  +#elif defined(HAVE_LOCALTIME_S) && HAVE_LOCALTIME_S
          432  +static int osLocaltime_s(time_t *t, struct tm *pTm){
          433  +  if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
          434  +  return (int)localtime_s(t, pTm);
          435  +}
          436  +#else
          437  +static struct tm * osLocaltime(time_t *t){
          438  +  if( sqlite3GlobalConfig.bLocaltimeFault ) return 0;
          439  +  return localtime(t);
          440  +}
          441  +#endif
          442  +
          443  +#else
          444  +# define osLocaltime_r(x,y) localtime_r(x,y)
          445  +# define osLocaltime_s(x,y) localtime_s(x,y)
          446  +# define osLocaltime(x)     localtime(x)
          447  +#endif
          448  +
          449  +
          450  +/*
          451  +** Compute the difference (in milliseconds) between localtime and UTC
          452  +** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs,
          453  +** return this value and set *pRc to SQLITE_OK. 
          454  +**
          455  +** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value
          456  +** is undefined in this case.
          457  +*/
          458  +static sqlite3_int64 localtimeOffset(
          459  +  DateTime *p,                    /* Date at which to calculate offset */
          460  +  sqlite3_context *pCtx,          /* Write error here if one occurs */
          461  +  int *pRc                        /* OUT: Error code. SQLITE_OK or ERROR */
          462  +){
   421    463     DateTime x, y;
   422    464     time_t t;
   423    465     x = *p;
   424    466     computeYMD_HMS(&x);
   425    467     if( x.Y<1971 || x.Y>=2038 ){
   426    468       x.Y = 2000;
   427    469       x.M = 1;
................................................................................
   436    478     x.tz = 0;
   437    479     x.validJD = 0;
   438    480     computeJD(&x);
   439    481     t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
   440    482   #ifdef HAVE_LOCALTIME_R
   441    483     {
   442    484       struct tm sLocal;
   443         -    localtime_r(&t, &sLocal);
          485  +    if( 0==osLocaltime_r(&t, &sLocal) ){
          486  +      sqlite3_result_error(pCtx, "error in localtime_r()", -1);
          487  +      *pRc = SQLITE_ERROR;
          488  +      return 0;
          489  +    }
   444    490       y.Y = sLocal.tm_year + 1900;
   445    491       y.M = sLocal.tm_mon + 1;
   446    492       y.D = sLocal.tm_mday;
   447    493       y.h = sLocal.tm_hour;
   448    494       y.m = sLocal.tm_min;
   449    495       y.s = sLocal.tm_sec;
   450    496     }
   451    497   #elif defined(HAVE_LOCALTIME_S) && HAVE_LOCALTIME_S
   452    498     {
   453    499       struct tm sLocal;
   454         -    localtime_s(&sLocal, &t);
          500  +    if( 0!=osLocaltime_s(&t, &sLocal) ){
          501  +      sqlite3_result_error(pCtx, "error in localtime_s()", -1);
          502  +      *pRc = SQLITE_ERROR;
          503  +      return 0;
          504  +    }
   455    505       y.Y = sLocal.tm_year + 1900;
   456    506       y.M = sLocal.tm_mon + 1;
   457    507       y.D = sLocal.tm_mday;
   458    508       y.h = sLocal.tm_hour;
   459    509       y.m = sLocal.tm_min;
   460    510       y.s = sLocal.tm_sec;
   461    511     }
   462    512   #else
   463    513     {
   464    514       struct tm *pTm;
   465    515       sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
   466         -    pTm = localtime(&t);
   467         -    y.Y = pTm->tm_year + 1900;
   468         -    y.M = pTm->tm_mon + 1;
   469         -    y.D = pTm->tm_mday;
   470         -    y.h = pTm->tm_hour;
   471         -    y.m = pTm->tm_min;
   472         -    y.s = pTm->tm_sec;
          516  +    pTm = osLocaltime(&t);
          517  +    if( pTm ){
          518  +      y.Y = pTm->tm_year + 1900;
          519  +      y.M = pTm->tm_mon + 1;
          520  +      y.D = pTm->tm_mday;
          521  +      y.h = pTm->tm_hour;
          522  +      y.m = pTm->tm_min;
          523  +      y.s = pTm->tm_sec;
          524  +    }
   473    525       sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
          526  +    if( !pTm ){
          527  +      sqlite3_result_error(pCtx, "error in localtime()", -1);
          528  +      *pRc = SQLITE_ERROR;
          529  +      return 0;
          530  +    }
   474    531     }
   475    532   #endif
   476    533     y.validYMD = 1;
   477    534     y.validHMS = 1;
   478    535     y.validJD = 0;
   479    536     y.validTZ = 0;
   480    537     computeJD(&y);
          538  +  *pRc = SQLITE_OK;
   481    539     return y.iJD - x.iJD;
   482    540   }
   483    541   #endif /* SQLITE_OMIT_LOCALTIME */
   484    542   
   485    543   /*
   486    544   ** Process a modifier to a date-time stamp.  The modifiers are
   487    545   ** as follows:
................................................................................
   497    555   **     start of week
   498    556   **     start of day
   499    557   **     weekday N
   500    558   **     unixepoch
   501    559   **     localtime
   502    560   **     utc
   503    561   **
   504         -** Return 0 on success and 1 if there is any kind of error.
          562  +** Return 0 on success and 1 if there is any kind of error. If the error
          563  +** is in a system call (i.e. localtime()), then an error message is written
          564  +** to context pCtx. If the error is an unrecognized modifier, no error is
          565  +** written to pCtx.
   505    566   */
   506         -static int parseModifier(const char *zMod, DateTime *p){
          567  +static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
   507    568     int rc = 1;
   508    569     int n;
   509    570     double r;
   510    571     char *z, zBuf[30];
   511    572     z = zBuf;
   512    573     for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){
   513    574       z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]];
................................................................................
   519    580         /*    localtime
   520    581         **
   521    582         ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
   522    583         ** show local time.
   523    584         */
   524    585         if( strcmp(z, "localtime")==0 ){
   525    586           computeJD(p);
   526         -        p->iJD += localtimeOffset(p);
          587  +        p->iJD += localtimeOffset(p, pCtx, &rc);
   527    588           clearYMD_HMS_TZ(p);
   528         -        rc = 0;
   529    589         }
   530    590         break;
   531    591       }
   532    592   #endif
   533    593       case 'u': {
   534    594         /*
   535    595         **    unixepoch
................................................................................
   542    602           clearYMD_HMS_TZ(p);
   543    603           rc = 0;
   544    604         }
   545    605   #ifndef SQLITE_OMIT_LOCALTIME
   546    606         else if( strcmp(z, "utc")==0 ){
   547    607           sqlite3_int64 c1;
   548    608           computeJD(p);
   549         -        c1 = localtimeOffset(p);
   550         -        p->iJD -= c1;
   551         -        clearYMD_HMS_TZ(p);
   552         -        p->iJD += c1 - localtimeOffset(p);
   553         -        rc = 0;
          609  +        c1 = localtimeOffset(p, pCtx, &rc);
          610  +        if( rc==SQLITE_OK ){
          611  +          p->iJD -= c1;
          612  +          clearYMD_HMS_TZ(p);
          613  +          p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
          614  +        }
   554    615         }
   555    616   #endif
   556    617         break;
   557    618       }
   558    619       case 'w': {
   559    620         /*
   560    621         **    weekday N
................................................................................
   727    788     }else{
   728    789       z = sqlite3_value_text(argv[0]);
   729    790       if( !z || parseDateOrTime(context, (char*)z, p) ){
   730    791         return 1;
   731    792       }
   732    793     }
   733    794     for(i=1; i<argc; i++){
   734         -    if( (z = sqlite3_value_text(argv[i]))==0 || parseModifier((char*)z, p) ){
   735         -      return 1;
   736         -    }
          795  +    z = sqlite3_value_text(argv[i]);
          796  +    if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
   737    797     }
   738    798     return 0;
   739    799   }
   740    800   
   741    801   
   742    802   /*
   743    803   ** The following routines implement the various date and time functions

Changes to src/main.c.

  2898   2898         sz = va_arg(ap, int);
  2899   2899         ppNew = va_arg(ap, void**);
  2900   2900         pFree = va_arg(ap, void*);
  2901   2901         if( sz ) *ppNew = sqlite3ScratchMalloc(sz);
  2902   2902         sqlite3ScratchFree(pFree);
  2903   2903         break;
  2904   2904       }
         2905  +
         2906  +    /*   sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
         2907  +    **
         2908  +    ** If parameter onoff is non-zero, configure the wrappers so that all
         2909  +    ** subsequent calls to localtime() and variants fail. If onoff is zero,
         2910  +    ** undo this setting.
         2911  +    */
         2912  +    case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
         2913  +      sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int);
         2914  +      break;
         2915  +    }
  2905   2916   
  2906   2917     }
  2907   2918     va_end(ap);
  2908   2919   #endif /* SQLITE_OMIT_BUILTIN_TEST */
  2909   2920     return rc;
  2910   2921   }
  2911   2922   

Changes to src/sqlite.h.in.

  5569   5569   #define SQLITE_TESTCTRL_ASSERT                  12
  5570   5570   #define SQLITE_TESTCTRL_ALWAYS                  13
  5571   5571   #define SQLITE_TESTCTRL_RESERVE                 14
  5572   5572   #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
  5573   5573   #define SQLITE_TESTCTRL_ISKEYWORD               16
  5574   5574   #define SQLITE_TESTCTRL_PGHDRSZ                 17
  5575   5575   #define SQLITE_TESTCTRL_SCRATCHMALLOC           18
  5576         -#define SQLITE_TESTCTRL_LAST                    18
         5576  +#define SQLITE_TESTCTRL_LOCALTIME_FAULT         19
         5577  +#define SQLITE_TESTCTRL_LAST                    19
  5577   5578   
  5578   5579   /*
  5579   5580   ** CAPI3REF: SQLite Runtime Status
  5580   5581   **
  5581   5582   ** ^This interface is used to retrieve runtime status information
  5582   5583   ** about the performance of SQLite, and optionally to reset various
  5583   5584   ** highwater marks.  ^The first argument is an integer code for

Changes to src/sqliteInt.h.

  2448   2448     int isMutexInit;                  /* True after mutexes are initialized */
  2449   2449     int isMallocInit;                 /* True after malloc is initialized */
  2450   2450     int isPCacheInit;                 /* True after malloc is initialized */
  2451   2451     sqlite3_mutex *pInitMutex;        /* Mutex used by sqlite3_initialize() */
  2452   2452     int nRefInitMutex;                /* Number of users of pInitMutex */
  2453   2453     void (*xLog)(void*,int,const char*); /* Function for logging */
  2454   2454     void *pLogArg;                       /* First argument to xLog() */
         2455  +  int bLocaltimeFault;              /* True to fail localtime() calls */
  2455   2456   };
  2456   2457   
  2457   2458   /*
  2458   2459   ** Context pointer passed down through the tree-walk.
  2459   2460   */
  2460   2461   struct Walker {
  2461   2462     int (*xExprCallback)(Walker*, Expr*);     /* Callback for expressions */

Changes to src/test1.c.

  5517   5517     }
  5518   5518     if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  5519   5519     rc = printExplainQueryPlan(pStmt);
  5520   5520     Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
  5521   5521     return TCL_OK;
  5522   5522   }
  5523   5523   #endif /* SQLITE_OMIT_EXPLAIN */
         5524  +
         5525  +/*
         5526  +** sqlite3_test_control VERB ARGS...
         5527  +*/
         5528  +static int test_test_control(
         5529  +  void * clientData,
         5530  +  Tcl_Interp *interp,
         5531  +  int objc,
         5532  +  Tcl_Obj *CONST objv[]
         5533  +){
         5534  +  struct Verb {
         5535  +    const char *zName;
         5536  +    int i;
         5537  +  } aVerb[] = {
         5538  +    { "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT }, 
         5539  +  };
         5540  +  int iVerb;
         5541  +  int iFlag;
         5542  +  int rc;
         5543  +
         5544  +  if( objc<2 ){
         5545  +    Tcl_WrongNumArgs(interp, 1, objv, "VERB ARGS...");
         5546  +    return TCL_ERROR;
         5547  +  }
         5548  +
         5549  +  rc = Tcl_GetIndexFromObjStruct(
         5550  +      interp, objv[1], aVerb, sizeof(aVerb[0]), "VERB", 0, &iVerb
         5551  +  );
         5552  +  if( rc!=TCL_OK ) return rc;
         5553  +
         5554  +  iFlag = aVerb[iVerb].i;
         5555  +  switch( iFlag ){
         5556  +    case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
         5557  +      int val;
         5558  +      if( objc!=3 ){
         5559  +        Tcl_WrongNumArgs(interp, 2, objv, "ONOFF");
         5560  +        return TCL_ERROR;
         5561  +      }
         5562  +      if( Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
         5563  +      sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, val);
         5564  +      break;
         5565  +    }
         5566  +  }
         5567  +
         5568  +  Tcl_ResetResult(interp);
         5569  +  return TCL_OK;
         5570  +}
         5571  +
  5524   5572   
  5525   5573   /*
  5526   5574   **      optimization_control DB OPT BOOLEAN
  5527   5575   **
  5528   5576   ** Enable or disable query optimizations using the sqlite3_test_control()
  5529   5577   ** interface.  Disable if BOOLEAN is false and enable if BOOLEAN is true.
  5530   5578   ** OPT is the name of the optimization to be disabled.
................................................................................
  5781   5829   #endif
  5782   5830        { "sqlite3_wal_checkpoint",   test_wal_checkpoint, 0  },
  5783   5831        { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0  },
  5784   5832        { "test_sqlite3_log",         test_sqlite3_log, 0  },
  5785   5833   #ifndef SQLITE_OMIT_EXPLAIN
  5786   5834        { "print_explain_query_plan", test_print_eqp, 0  },
  5787   5835   #endif
         5836  +     { "sqlite3_test_control", test_test_control },
  5788   5837     };
  5789   5838     static int bitmask_size = sizeof(Bitmask)*8;
  5790   5839     int i;
  5791   5840     extern int sqlite3_sync_count, sqlite3_fullsync_count;
  5792   5841     extern int sqlite3_opentemp_count;
  5793   5842     extern int sqlite3_like_count;
  5794   5843     extern int sqlite3_xferopt_count;

Added test/tkt-bd484a090c.test.

            1  +# 2011 June 21
            2  +#
            3  +#    May you do good and not evil.
            4  +#    May you find forgiveness for yourself and forgive others.
            5  +#    May you share freely, never taking more than you give.
            6  +#
            7  +#***********************************************************************
            8  +#
            9  +# This file contains tests for SQLite. Specifically, it tests that SQLite
           10  +# does not crash and an error is returned if localhost() fails. This 
           11  +# is the problem reported by ticket bd484a090c.
           12  +#
           13  +
           14  +set testdir [file dirname $argv0]
           15  +source $testdir/tester.tcl
           16  +
           17  +set testprefix tkt-bd484a090c
           18  +
           19  +
           20  +do_test 1.1 {
           21  +  lindex [catchsql { SELECT datetime('now', 'localtime') }] 0
           22  +} {0}
           23  +do_test 1.2 {
           24  +  lindex [catchsql { SELECT datetime('now', 'utc') }] 0
           25  +} {0}
           26  +
           27  +sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 1
           28  +
           29  +do_test 2.1 {
           30  +  foreach {rc msg} [catchsql { SELECT datetime('now', 'localtime') }] {}
           31  +  set res [string match {error in localtime*()} $msg]
           32  +  list $rc $res
           33  +} {1 1}
           34  +do_test 2.2 {
           35  +  foreach {rc msg} [catchsql { SELECT datetime('now', 'utc') }] {}
           36  +  set res [string match {error in localtime*()} $msg]
           37  +  list $rc $res
           38  +} {1 1}
           39  +
           40  +sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 0
           41  +
           42  +finish_test