/ Check-in [86eab9e5]
Login

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

Overview
Comment:Handle malloc() failures that occur in open16() and errmsg16(). (CVS 2967)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:86eab9e53db8d7fecc789fe3d8cd8d7be3196fed
User & Date: danielk1977 2006-01-18 05:51:58
Context
2006-01-18
14:06
Convert the unix driver to use a recusive mutex. Similar changes to the windows driver are pending. (CVS 2968) check-in: 8830bbba user: drh tags: trunk
05:51
Handle malloc() failures that occur in open16() and errmsg16(). (CVS 2967) check-in: 86eab9e5 user: danielk1977 tags: trunk
04:26
Handle malloc() failures that occur inside create_collation() calls. (CVS 2966) check-in: 95c5903f user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/main.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
723
724
725
726
727
728
729

730
731
732
733
734
735
736
...
926
927
928
929
930
931
932




933
934
935
936
937
938
939
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.325 2006/01/18 04:26:07 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** The following constant value is used by the SQLITE_BIGENDIAN and
................................................................................
  }
  z = sqlite3_value_text16(db->pErr);
  if( z==0 ){
    sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode),
         SQLITE_UTF8, SQLITE_STATIC);
    z = sqlite3_value_text16(db->pErr);
  }

  return z;
}
#endif /* SQLITE_OMIT_UTF16 */

/*
** Return the most recent error code generated by an SQLite routine. If NULL is
** passed to this function, we assume a malloc() failed during sqlite3_open().
................................................................................
  pVal = sqlite3ValueNew();
  sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
  zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
  if( zFilename8 ){
    rc = openDatabase(zFilename8, ppDb);
    if( rc==SQLITE_OK && *ppDb ){
      rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);




    }
  }else{
    assert( sqlite3ThreadDataReadOnly()->mallocFailed );
    sqlite3MallocClearFailed();
  }
  sqlite3ValueFree(pVal);








|







 







>







 







>
>
>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
...
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.326 2006/01/18 05:51:58 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** The following constant value is used by the SQLITE_BIGENDIAN and
................................................................................
  }
  z = sqlite3_value_text16(db->pErr);
  if( z==0 ){
    sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode),
         SQLITE_UTF8, SQLITE_STATIC);
    z = sqlite3_value_text16(db->pErr);
  }
  sqlite3MallocClearFailed();
  return z;
}
#endif /* SQLITE_OMIT_UTF16 */

/*
** Return the most recent error code generated by an SQLite routine. If NULL is
** passed to this function, we assume a malloc() failed during sqlite3_open().
................................................................................
  pVal = sqlite3ValueNew();
  sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
  zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
  if( zFilename8 ){
    rc = openDatabase(zFilename8, ppDb);
    if( rc==SQLITE_OK && *ppDb ){
      rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
      if( rc!=SQLITE_OK ){
        sqlite3_close(*ppDb);
        *ppDb = 0;
      }
    }
  }else{
    assert( sqlite3ThreadDataReadOnly()->mallocFailed );
    sqlite3MallocClearFailed();
  }
  sqlite3ValueFree(pVal);

Changes to src/test1.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
....
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061

2062

2063
2064
2065
2066
2067
2068
2069
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the printf() interface to SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.194 2006/01/18 04:26:07 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

................................................................................
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
  sqlite3 *db;
  const void *zErr;
  int bytes;

  if( objc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " DB", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;

  zErr = sqlite3_errmsg16(db);

  bytes = sqlite3utf16ByteLen(zErr, -1);

  Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
#endif /* SQLITE_OMIT_UTF16 */
  return TCL_OK;
}

/*
** Usage: sqlite3_prepare DB sql bytes tailvar







|







 







|









>
|
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
....
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the printf() interface to SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.195 2006/01/18 05:51:58 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

................................................................................
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
  sqlite3 *db;
  const void *zErr;
  int bytes = 0;

  if( objc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " DB", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;

  zErr = sqlite3_errmsg16(db);
  if( zErr ){
    bytes = sqlite3utf16ByteLen(zErr, -1);
  }
  Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
#endif /* SQLITE_OMIT_UTF16 */
  return TCL_OK;
}

/*
** Usage: sqlite3_prepare DB sql bytes tailvar

Changes to src/vdbeapi.c.

776
777
778
779
780
781
782

783

784
785
786
787
788
789
790
791
792
793
794
795
796
    || (pTo->magic!=VDBE_MAGIC_RUN && pTo->magic!=VDBE_MAGIC_HALT) ){
    return SQLITE_MISUSE;
  }
  if( pFrom->nVar!=pTo->nVar ){
    return SQLITE_ERROR;
  }
  for(i=0; rc==SQLITE_OK && i<pFrom->nVar; i++){

    rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);

  }
  return rc;
}

/*
** Return the sqlite3* database handle to which the prepared statement given
** in the argument belongs.  This is the same database handle that was
** the first argument to the sqlite3_prepare() that was used to create
** the statement in the first place.
*/
sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
  return pStmt ? ((Vdbe*)pStmt)->db : 0;
}







>

>













776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
    || (pTo->magic!=VDBE_MAGIC_RUN && pTo->magic!=VDBE_MAGIC_HALT) ){
    return SQLITE_MISUSE;
  }
  if( pFrom->nVar!=pTo->nVar ){
    return SQLITE_ERROR;
  }
  for(i=0; rc==SQLITE_OK && i<pFrom->nVar; i++){
    sqlite3MallocDisallow();
    rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
    sqlite3MallocAllow();
  }
  return rc;
}

/*
** Return the sqlite3* database handle to which the prepared statement given
** in the argument belongs.  This is the same database handle that was
** the first argument to the sqlite3_prepare() that was used to create
** the statement in the first place.
*/
sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
  return pStmt ? ((Vdbe*)pStmt)->db : 0;
}

Changes to test/malloc.test.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
...
355
356
357
358
359
360
361
362
363

364
365




366
367
368
369
370
371
372
...
390
391
392
393
394
395
396

397
398
399
400
401
402




403
404
405
406
407
408


































































409
410
411
412
413
414
415
416
417
#***********************************************************************
# This file attempts to check the library in an out-of-memory situation.
# When compiled with -DSQLITE_DEBUG=1, the SQLite library accepts a special
# command (sqlite_malloc_fail N) which causes the N-th malloc to fail.  This
# special feature is used to see what happens in the library if a malloc
# were to really fail due to an out-of-memory situation.
#
# $Id: malloc.test,v 1.28 2006/01/18 04:26:08 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
if {[info command sqlite_malloc_stat]==""} {
................................................................................
        set v2 [expr {$msg=="" || $msg=="out of memory"}]
        if {!$v2} {puts "\nError message returned: $msg"}
        lappend v $v2
      }
    } {1 1}

    if {[info exists ::mallocopts(-cleanup)]} {
      catch $::mallocopts(-cleanup)
    }
  }
  unset ::mallocopts
}

do_malloc_test 1 -tclprep {
  db close
................................................................................
      CREATE TABLE aux.t2(a, b, c);
      CREATE TABLE t1(a, b, c);
      COMMIT;
    }]
    if {$rc!="1 {child process exited abnormally}"} {
      error "Wrong error message: $rc"
    }
  } -sqlbody {
    ATTACH 'test2.db' as aux;

    SELECT * FROM t1;
    SELECT * FROM t2;




  }
}

if {$tcl_platform(platform)!="windows"} {
  do_malloc_test 14 -tclprep {
    catch {db close}
    sqlite3 db2 test2.db
................................................................................

proc string_compare {a b} {
  return [string compare $a $b]
}

# Test for malloc() failures in sqlite3_create_collation() and 
# sqlite3_create_collation16().

do_malloc_test 15 -tclbody {
  db collate string_compare string_compare
  if {[catch {add_test_collate $::DB 1 1 1} msg]} {
    if {$msg=="SQLITE_NOMEM"} {set msg "out of memory"}
    error $msg
  }




  execsql {
    CREATE TABLE t1(a, b COLLATE string_compare);
    INSERT INTO t1 VALUES(10, 'string');
    INSERT INTO t1 VALUES(10, 'string2');
  }
}



































































# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
  catch {db close}
  set sqlite_open_file_count
} {0}

sqlite_malloc_fail 0
finish_test







|







 







|







 







|
|
>
|
|
>
>
>
>







 







>






>
>
>
>






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









10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
...
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
#***********************************************************************
# This file attempts to check the library in an out-of-memory situation.
# When compiled with -DSQLITE_DEBUG=1, the SQLite library accepts a special
# command (sqlite_malloc_fail N) which causes the N-th malloc to fail.  This
# special feature is used to see what happens in the library if a malloc
# were to really fail due to an out-of-memory situation.
#
# $Id: malloc.test,v 1.29 2006/01/18 05:51:58 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
if {[info command sqlite_malloc_stat]==""} {
................................................................................
        set v2 [expr {$msg=="" || $msg=="out of memory"}]
        if {!$v2} {puts "\nError message returned: $msg"}
        lappend v $v2
      }
    } {1 1}

    if {[info exists ::mallocopts(-cleanup)]} {
      catch [list uplevel #0 $::mallocopts(-cleanup)] msg
    }
  }
  unset ::mallocopts
}

do_malloc_test 1 -tclprep {
  db close
................................................................................
      CREATE TABLE aux.t2(a, b, c);
      CREATE TABLE t1(a, b, c);
      COMMIT;
    }]
    if {$rc!="1 {child process exited abnormally}"} {
      error "Wrong error message: $rc"
    }
  } -tclbody {
    db eval {ATTACH 'test2.db' as aux;}
    set rc [catch {db eval {
      SELECT * FROM t1; 
      SELECT * FROM t2;
    }} err]
    if {$rc && $err!="no such table: t1"} {
      error $err
    }
  }
}

if {$tcl_platform(platform)!="windows"} {
  do_malloc_test 14 -tclprep {
    catch {db close}
    sqlite3 db2 test2.db
................................................................................

proc string_compare {a b} {
  return [string compare $a $b]
}

# Test for malloc() failures in sqlite3_create_collation() and 
# sqlite3_create_collation16().
#
do_malloc_test 15 -tclbody {
  db collate string_compare string_compare
  if {[catch {add_test_collate $::DB 1 1 1} msg]} {
    if {$msg=="SQLITE_NOMEM"} {set msg "out of memory"}
    error $msg
  }

  db complete {SELECT "hello """||'world"' [microsoft], * FROM anicetable;}
  db complete {-- Useful comment}

  execsql {
    CREATE TABLE t1(a, b COLLATE string_compare);
    INSERT INTO t1 VALUES(10, 'string');
    INSERT INTO t1 VALUES(10, 'string2');
  }
}

# Also test sqlite3_complete(). There are (currently) no malloc()
# calls in this function, but test anyway against future changes.
#
do_malloc_test 16 -tclbody {
  db complete {SELECT "hello """||'world"' [microsoft], * FROM anicetable;}
  db complete {-- Useful comment}
  db eval {
    SELECT * FROM sqlite_master;
  }
}

# Test handling of malloc() failures in sqlite3_open16().
#
do_malloc_test 17 -tclbody {
  set DB2 0
  set STMT 0

  # open database using sqlite3_open16()
  set DB2 [sqlite3_open16 test.db -unused]
  if {0==$DB2} {
    error "out of memory"
  }

  # Prepare statement
  set rc [catch {sqlite3_prepare $DB2 {SELECT * FROM sqlite_master} -1 X} msg]
  if {$rc} {
    error [string range $msg 4 end]
  }
  set STMT $msg

  # Finalize statement
  set rc [sqlite3_finalize $STMT]
  if {$rc!="SQLITE_OK"} {
    error [sqlite3_errmsg $DB2]
  }
  set STMT 0

  # Close database
  set rc [sqlite3_close $DB2]
  if {$rc!="SQLITE_OK"} {
    error [sqlite3_errmsg $DB2]
  }
  set DB2 0
} -cleanup {
  if {$STMT!="0"} {
    sqlite3_finalize $STMT
  }
  if {$DB2!="0"} {
    set rc [sqlite3_close $DB2]
  }
}

# Test handling of malloc() failures in sqlite3_errmsg16().
#
do_malloc_test 18 -tclbody {
  catch {
    db eval "SELECT [string repeat longcolumnname 10] FROM sqlite_master"
  } msg
  if {$msg=="out of memory"} {error $msg}
  set utf16 [sqlite3_errmsg16 [sqlite3_connection_pointer db]]
  binary scan $utf16 c* bytes
  if {[llength $bytes]==0} {
    error "out of memory"
  }
}

# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
  catch {db close}
  set sqlite_open_file_count
} {0}

sqlite_malloc_fail 0
finish_test