SQLite

Check-in [8dedd6ad44]
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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8dedd6ad44bd1d103dced9d1350188cb2327128d
User & Date: dan 2016-12-17 08:18:05.241
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: ef6e071a62 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: 8dedd6ad44 user: dan tags: trunk)
2016-12-16
18:43
Add the ".lint fkey-indexes" command to the command-line shell. (check-in: 94689e3bda user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/shell.c.
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286

2287







2288

2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307

2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322

2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
}
#endif


/* Forward reference */
static int process_input(ShellState *p, FILE *in);


/*
** Read the content of a file into memory obtained from sqlite3_malloc64().
** The caller is responsible for freeing the memory.

**







** NULL is returned if any error is encountered.

*/
static char *readFile(const char *zName){
  FILE *in = fopen(zName, "rb");
  long nIn;
  size_t nRead;
  char *pBuf;
  if( in==0 ) return 0;
  fseek(in, 0, SEEK_END);
  nIn = ftell(in);
  rewind(in);
  pBuf = sqlite3_malloc64( nIn+1 );
  if( pBuf==0 ) return 0;
  nRead = fread(pBuf, nIn, 1, in);
  fclose(in);
  if( nRead!=1 ){
    sqlite3_free(pBuf);
    return 0;
  }
  pBuf[nIn] = 0;

  return pBuf;
}

/*
** Implementation of the "readfile(X)" SQL function.  The entire content
** of the file named X is read and returned as a BLOB.  NULL is returned
** if the file does not exist or is unreadable.
*/
static void readfileFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zName;
  void *pBuf;


  UNUSED_PARAMETER(argc);
  zName = (const char*)sqlite3_value_text(argv[0]);
  if( zName==0 ) return;
  pBuf = readFile(zName);
  if( pBuf ) sqlite3_result_blob(context, pBuf, -1, sqlite3_free);
}

/*
** Implementation of the "writefile(X,Y)" SQL function.  The argument Y
** is written into file X.  The number of bytes written is returned.  Or
** NULL is returned if something goes wrong, such as being unable to open
** file X for writing.







<

|
|
>

>
>
>
>
>
>
>
|
>

|

















>















>




|
|







2276
2277
2278
2279
2280
2281
2282

2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
}
#endif


/* Forward reference */
static int process_input(ShellState *p, FILE *in);


/*
** Read the content of file zName into memory obtained from sqlite3_malloc64()
** and return a pointer to the buffer. The caller is responsible for freeing 
** the memory. 
**
** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
** read.
**
** For convenience, a nul-terminator byte is always appended to the data read
** from the file before the buffer is returned. This byte is not included in
** the final value of (*pnByte), if applicable.
**
** NULL is returned if any error is encountered. The final value of *pnByte
** is undefined in this case.
*/
static char *readFile(const char *zName, int *pnByte){
  FILE *in = fopen(zName, "rb");
  long nIn;
  size_t nRead;
  char *pBuf;
  if( in==0 ) return 0;
  fseek(in, 0, SEEK_END);
  nIn = ftell(in);
  rewind(in);
  pBuf = sqlite3_malloc64( nIn+1 );
  if( pBuf==0 ) return 0;
  nRead = fread(pBuf, nIn, 1, in);
  fclose(in);
  if( nRead!=1 ){
    sqlite3_free(pBuf);
    return 0;
  }
  pBuf[nIn] = 0;
  if( pnByte ) *pnByte = nIn;
  return pBuf;
}

/*
** Implementation of the "readfile(X)" SQL function.  The entire content
** of the file named X is read and returned as a BLOB.  NULL is returned
** if the file does not exist or is unreadable.
*/
static void readfileFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zName;
  void *pBuf;
  int nBuf;

  UNUSED_PARAMETER(argc);
  zName = (const char*)sqlite3_value_text(argv[0]);
  if( zName==0 ) return;
  pBuf = readFile(zName, &nBuf);
  if( pBuf ) sqlite3_result_blob(context, pBuf, nBuf, sqlite3_free);
}

/*
** Implementation of the "writefile(X,Y)" SQL function.  The argument Y
** is written into file X.  The number of bytes written is returned.  Or
** NULL is returned if something goes wrong, such as being unable to open
** file X for writing.
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
  */
  if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
    char *zRes = 0;
    output_reset(p);
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
      rc = 2;
    }else if( (zRes = readFile("testcase-out.txt"))==0 ){
      raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
      rc = 2;
    }else if( testcase_glob(azArg[1],zRes)==0 ){
      utf8_printf(stderr,
                 "testcase-%s FAILED\n Expected: [%s]\n      Got: [%s]\n",
                 p->zTestcase, azArg[1], zRes);
      rc = 2;







|







3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
  */
  if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
    char *zRes = 0;
    output_reset(p);
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
      rc = 2;
    }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
      raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
      rc = 2;
    }else if( testcase_glob(azArg[1],zRes)==0 ){
      utf8_printf(stderr,
                 "testcase-%s FAILED\n Expected: [%s]\n      Got: [%s]\n",
                 p->zTestcase, azArg[1], zRes);
      rc = 2;
Changes to test/shell6.test.
1
2
3
4
5
6
7
8
9
10


11
12
13
14
15
16
17
# 2016 December 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************


#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix shell6
set CLI [test_find_cli]
db close










>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 2016 December 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Test the shell tool ".lint fkey-indexes" command.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix shell6
set CLI [test_find_cli]
db close
Added test/shell7.test.












































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 2016 December 17
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Test the readfile() function built into the shell tool. Specifically,
# that it does not truncate the blob read at the first embedded 0x00
# byte.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix shell7
set CLI [test_find_cli]


do_execsql_test 1.0 { 
  CREATE TABLE f1(tn INTEGER PRIMARY KEY, x BLOB); 
  CREATE TABLE f2(tn INTEGER PRIMARY KEY, x BLOB); 

  INSERT INTO f1 VALUES(1, X'01020304');
  INSERT INTO f1 VALUES(2, X'01000304');
  INSERT INTO f1 VALUES(3, randomblob(200));
}

foreach {tn l x} [db eval { SELECT tn, length(x) AS l, x FROM f1 }] {
  forcedelete shell7_test.bin
  set fd [open shell7_test.bin w]
  fconfigure $fd -encoding binary
  fconfigure $fd -translation binary
  puts -nonewline $fd $x
  close $fd

  do_test 1.$tn.1 { file size shell7_test.bin } $l
  do_test 1.$tn.2 { 
    catchcmd test.db "INSERT INTO f2 VALUES($tn, readfile('shell7_test.bin'));"
  } {0 {}}

  do_execsql_test 1.$tn.3 { 
    SELECT (SELECT x FROM f1 WHERE tn=1)==(SELECT x FROM f2 WHERE tn=1)
  } {1}
}



finish_test