/ Check-in [8dedd6ad]
Login

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

Overview
Comment:Fix a problem in the shell tools readfile() command causing blobs to be truncated at the first embedded 0x00 byte in release builds, or an assert() to fail in a debug build.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8dedd6ad44bd1d103dced9d1350188cb2327128d
User & Date: dan 2016-12-17 08:18:05
Context
2016-12-17
20:27
Enhance fuzzershell.c to read and execute SQL commands in the autoexec table of the database under test. Add the dbfuzz.c test program combining selected features of fuzzershell.c and fuzzcheck.c. check-in: ef6e071a user: drh tags: trunk
08:18
Fix a problem in the shell tools readfile() command causing blobs to be truncated at the first embedded 0x00 byte in release builds, or an assert() to fail in a debug build. check-in: 8dedd6ad user: dan tags: trunk
2016-12-16
18:43
Add the ".lint fkey-indexes" command to the command-line shell. check-in: 94689e3b user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/shell.c.

  2276   2276   }
  2277   2277   #endif
  2278   2278   
  2279   2279   
  2280   2280   /* Forward reference */
  2281   2281   static int process_input(ShellState *p, FILE *in);
  2282   2282   
  2283         -
  2284   2283   /*
  2285         -** Read the content of a file into memory obtained from sqlite3_malloc64().
  2286         -** The caller is responsible for freeing the memory.
         2284  +** Read the content of file zName into memory obtained from sqlite3_malloc64()
         2285  +** and return a pointer to the buffer. The caller is responsible for freeing 
         2286  +** the memory. 
  2287   2287   **
  2288         -** NULL is returned if any error is encountered.
         2288  +** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
         2289  +** read.
         2290  +**
         2291  +** For convenience, a nul-terminator byte is always appended to the data read
         2292  +** from the file before the buffer is returned. This byte is not included in
         2293  +** the final value of (*pnByte), if applicable.
         2294  +**
         2295  +** NULL is returned if any error is encountered. The final value of *pnByte
         2296  +** is undefined in this case.
  2289   2297   */
  2290         -static char *readFile(const char *zName){
         2298  +static char *readFile(const char *zName, int *pnByte){
  2291   2299     FILE *in = fopen(zName, "rb");
  2292   2300     long nIn;
  2293   2301     size_t nRead;
  2294   2302     char *pBuf;
  2295   2303     if( in==0 ) return 0;
  2296   2304     fseek(in, 0, SEEK_END);
  2297   2305     nIn = ftell(in);
................................................................................
  2301   2309     nRead = fread(pBuf, nIn, 1, in);
  2302   2310     fclose(in);
  2303   2311     if( nRead!=1 ){
  2304   2312       sqlite3_free(pBuf);
  2305   2313       return 0;
  2306   2314     }
  2307   2315     pBuf[nIn] = 0;
         2316  +  if( pnByte ) *pnByte = nIn;
  2308   2317     return pBuf;
  2309   2318   }
  2310   2319   
  2311   2320   /*
  2312   2321   ** Implementation of the "readfile(X)" SQL function.  The entire content
  2313   2322   ** of the file named X is read and returned as a BLOB.  NULL is returned
  2314   2323   ** if the file does not exist or is unreadable.
................................................................................
  2316   2325   static void readfileFunc(
  2317   2326     sqlite3_context *context,
  2318   2327     int argc,
  2319   2328     sqlite3_value **argv
  2320   2329   ){
  2321   2330     const char *zName;
  2322   2331     void *pBuf;
         2332  +  int nBuf;
  2323   2333   
  2324   2334     UNUSED_PARAMETER(argc);
  2325   2335     zName = (const char*)sqlite3_value_text(argv[0]);
  2326   2336     if( zName==0 ) return;
  2327         -  pBuf = readFile(zName);
  2328         -  if( pBuf ) sqlite3_result_blob(context, pBuf, -1, sqlite3_free);
         2337  +  pBuf = readFile(zName, &nBuf);
         2338  +  if( pBuf ) sqlite3_result_blob(context, pBuf, nBuf, sqlite3_free);
  2329   2339   }
  2330   2340   
  2331   2341   /*
  2332   2342   ** Implementation of the "writefile(X,Y)" SQL function.  The argument Y
  2333   2343   ** is written into file X.  The number of bytes written is returned.  Or
  2334   2344   ** NULL is returned if something goes wrong, such as being unable to open
  2335   2345   ** file X for writing.
................................................................................
  3661   3671     */
  3662   3672     if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
  3663   3673       char *zRes = 0;
  3664   3674       output_reset(p);
  3665   3675       if( nArg!=2 ){
  3666   3676         raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
  3667   3677         rc = 2;
  3668         -    }else if( (zRes = readFile("testcase-out.txt"))==0 ){
         3678  +    }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
  3669   3679         raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
  3670   3680         rc = 2;
  3671   3681       }else if( testcase_glob(azArg[1],zRes)==0 ){
  3672   3682         utf8_printf(stderr,
  3673   3683                    "testcase-%s FAILED\n Expected: [%s]\n      Got: [%s]\n",
  3674   3684                    p->zTestcase, azArg[1], zRes);
  3675   3685         rc = 2;

Changes to test/shell6.test.

     4      4   # a legal notice, here is a blessing:
     5      5   #
     6      6   #    May you do good and not evil.
     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
           11  +#
           12  +# Test the shell tool ".lint fkey-indexes" command.
    11     13   #
    12     14   
    13     15   set testdir [file dirname $argv0]
    14     16   source $testdir/tester.tcl
    15     17   set testprefix shell6
    16     18   set CLI [test_find_cli]
    17     19   db close

Added test/shell7.test.

            1  +# 2016 December 17
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +# Test the readfile() function built into the shell tool. Specifically,
           13  +# that it does not truncate the blob read at the first embedded 0x00
           14  +# byte.
           15  +#
           16  +
           17  +set testdir [file dirname $argv0]
           18  +source $testdir/tester.tcl
           19  +set testprefix shell7
           20  +set CLI [test_find_cli]
           21  +
           22  +
           23  +do_execsql_test 1.0 { 
           24  +  CREATE TABLE f1(tn INTEGER PRIMARY KEY, x BLOB); 
           25  +  CREATE TABLE f2(tn INTEGER PRIMARY KEY, x BLOB); 
           26  +
           27  +  INSERT INTO f1 VALUES(1, X'01020304');
           28  +  INSERT INTO f1 VALUES(2, X'01000304');
           29  +  INSERT INTO f1 VALUES(3, randomblob(200));
           30  +}
           31  +
           32  +foreach {tn l x} [db eval { SELECT tn, length(x) AS l, x FROM f1 }] {
           33  +  forcedelete shell7_test.bin
           34  +  set fd [open shell7_test.bin w]
           35  +  fconfigure $fd -encoding binary
           36  +  fconfigure $fd -translation binary
           37  +  puts -nonewline $fd $x
           38  +  close $fd
           39  +
           40  +  do_test 1.$tn.1 { file size shell7_test.bin } $l
           41  +  do_test 1.$tn.2 { 
           42  +    catchcmd test.db "INSERT INTO f2 VALUES($tn, readfile('shell7_test.bin'));"
           43  +  } {0 {}}
           44  +
           45  +  do_execsql_test 1.$tn.3 { 
           46  +    SELECT (SELECT x FROM f1 WHERE tn=1)==(SELECT x FROM f2 WHERE tn=1)
           47  +  } {1}
           48  +}
           49  +
           50  +
           51  +
           52  +finish_test
           53  +
           54  +