/ Check-in [f095cde5]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Fix a buffer overread during compilation of CREATE VIRTUAL TABLE statements that featured an explicit database name but no virtual table arguments. For example, "CREATE VIRTUAL TABLE main.ft USING fts4".
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f095cde579e7417306e11b5c1d2dd90b6bb547d5
User & Date: dan 2014-11-27 11:36:36
Context
2014-11-28
11:54
Add the -end option to the command-line shell, which forces it to exit after reading prior command-line options (presumably including one or more -cmd options) and without reading standard input. check-in: b59397b1 user: drh tags: trunk
2014-11-27
11:36
Fix a buffer overread during compilation of CREATE VIRTUAL TABLE statements that featured an explicit database name but no virtual table arguments. For example, "CREATE VIRTUAL TABLE main.ft USING fts4". check-in: f095cde5 user: dan tags: trunk
04:23
More test cases for the balancer. check-in: 358ea818 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/test1.c.

3634
3635
3636
3637
3638
3639
3640

3641
3642
3643
3644
3645
3646
3647
....
3649
3650
3651
3652
3653
3654
3655











3656



3657
3658
3659
3660
3661
3662
3663
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db;
  const char *zSql;

  int bytes;
  const char *zTail = 0;
  sqlite3_stmt *pStmt = 0;
  char zBuf[50];
  int rc;

  if( objc!=5 && objc!=4 ){
................................................................................
       Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zSql = Tcl_GetString(objv[2]);
  if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;












  rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);



  assert(rc==SQLITE_OK || pStmt==0);
  Tcl_ResetResult(interp);
  if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
  if( zTail && objc>=5 ){
    if( bytes>=0 ){
      bytes = bytes - (int)(zTail-zSql);
    }







>







 







>
>
>
>
>
>
>
>
>
>
>
|
>
>
>







3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
....
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db;
  const char *zSql;
  char *zCopy = 0;                /* malloc() copy of zSql */
  int bytes;
  const char *zTail = 0;
  sqlite3_stmt *pStmt = 0;
  char zBuf[50];
  int rc;

  if( objc!=5 && objc!=4 ){
................................................................................
       Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zSql = Tcl_GetString(objv[2]);
  if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;

  /* Instead of using zSql directly, make a copy into a buffer obtained
  ** directly from malloc(). The idea is to make it easier for valgrind
  ** to spot buffer overreads.  */
  if( bytes>=0 ){
    zCopy = malloc(bytes);
    memcpy(zCopy, zSql, bytes);
  }else{
    int n = strlen(zSql) + 1;
    zCopy = malloc(n);
    memcpy(zCopy, zSql, n);
  }
  rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, objc>=5 ? &zTail : 0);
  free(zCopy);
  zTail = &zSql[(zTail - zCopy)];

  assert(rc==SQLITE_OK || pStmt==0);
  Tcl_ResetResult(interp);
  if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
  if( zTail && objc>=5 ){
    if( bytes>=0 ){
      bytes = bytes - (int)(zTail-zSql);
    }

Changes to src/vtab.c.

328
329
330
331
332
333
334



335


336
337
338
339
340
341
342
  assert( iDb>=0 );

  pTable->tabFlags |= TF_Virtual;
  pTable->nModuleArg = 0;
  addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
  addModuleArgument(db, pTable, 0);
  addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));



  pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);



#ifndef SQLITE_OMIT_AUTHORIZATION
  /* Creating a virtual table invokes the authorization callback twice.
  ** The first invocation, to obtain permission to INSERT a row into the
  ** sqlite_master table, has already been made by sqlite3StartTable().
  ** The second call, to obtain permission to create the table, is made now.
  */







>
>
>
|
>
>







328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
  assert( iDb>=0 );

  pTable->tabFlags |= TF_Virtual;
  pTable->nModuleArg = 0;
  addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
  addModuleArgument(db, pTable, 0);
  addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
  assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0)
       || (pParse->sNameToken.z==pName1->z && pName2->z==0)
  );
  pParse->sNameToken.n = (int)(
      &pModuleName->z[pModuleName->n] - pParse->sNameToken.z
  );

#ifndef SQLITE_OMIT_AUTHORIZATION
  /* Creating a virtual table invokes the authorization callback twice.
  ** The first invocation, to obtain permission to INSERT a row into the
  ** sqlite_master table, has already been made by sqlite3StartTable().
  ** The second call, to obtain permission to create the table, is made now.
  */

Changes to test/vtab1.test.

1390
1391
1392
1393
1394
1395
1396
1397










































1398
do_execsql_test 21.2 {
  SELECT * FROM t9v WHERE a<b;
} {1 2 3}

do_execsql_test 21.3 {
  SELECT * FROM t9v WHERE a=b;
} {2 2 2}











































finish_test








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
do_execsql_test 21.2 {
  SELECT * FROM t9v WHERE a<b;
} {1 2 3}

do_execsql_test 21.3 {
  SELECT * FROM t9v WHERE a=b;
} {2 2 2}

#-------------------------------------------------------------------------
# At one point executing a CREATE VIRTUAL TABLE statement that specified 
# a database name but no virtual table arguments was causing an internal
# buffer overread. Valgrind would report errors while running the following 
# tests. Specifically:
#
#   CREATE VIRTUAL TABLE t1 USING fts4;          -- Ok - no db name.
#   CREATE VIRTUAL TABLE main.t1 USING fts4(x);  -- Ok - has vtab arguments.
#   CREATE VIRTUAL TABLE main.t1 USING fts4;     -- Had the problem. 
#
ifcapable fts3 {
  forcedelete test.db2
  set nm [string repeat abcdefghij 100]
  do_execsql_test 22.1 {
    ATTACH 'test.db2' AS $nm
  }
  
  execsql "SELECT * FROM sqlite_master"
  do_execsql_test 22.2 "CREATE VIRTUAL TABLE ${nm}.t1 USING fts4"
  
  do_test 22.3.1 {
    set sql "CREATE VIRTUAL TABLE ${nm}.t2 USING fts4"
    set stmt [sqlite3_prepare_v2 db $sql -1 dummy]
    sqlite3_step $stmt
  } {SQLITE_DONE}
  
  do_test 22.3.2 {
    sqlite3_finalize $stmt
  } {SQLITE_OK}
  
  do_test 22.4.1 {
    set sql "CREATE VIRTUAL TABLE ${nm}.t3 USING fts4"
    set n [string length $sql]
    set stmt [sqlite3_prepare db "${sql}xyz" $n dummy]
    sqlite3_step $stmt
  } {SQLITE_DONE}
  
  do_test 22.4.2 {
    sqlite3_finalize $stmt
  } {SQLITE_OK}
}

finish_test