Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -12,11 +12,11 @@ ** 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 $ +** $Id: main.c,v 1.326 2006/01/18 05:51:58 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -725,10 +725,11 @@ 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 */ /* @@ -928,10 +929,14 @@ 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(); } Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -11,11 +11,11 @@ ************************************************************************* ** 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 $ +** $Id: test1.c,v 1.195 2006/01/18 05:51:58 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include "os.h" #include @@ -2047,21 +2047,23 @@ Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3 *db; const void *zErr; - int bytes; + 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); - bytes = sqlite3utf16ByteLen(zErr, -1); + if( zErr ){ + bytes = sqlite3utf16ByteLen(zErr, -1); + } Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes)); #endif /* SQLITE_OMIT_UTF16 */ return TCL_OK; } Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -778,11 +778,13 @@ } if( pFrom->nVar!=pTo->nVar ){ return SQLITE_ERROR; } for(i=0; rc==SQLITE_OK && inVar; i++){ + sqlite3MallocDisallow(); rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]); + sqlite3MallocAllow(); } return rc; } /* Index: test/malloc.test ================================================================== --- test/malloc.test +++ test/malloc.test @@ -12,11 +12,11 @@ # 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 $ +# $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. @@ -108,11 +108,11 @@ lappend v $v2 } } {1 1} if {[info exists ::mallocopts(-cleanup)]} { - catch $::mallocopts(-cleanup) + catch [list uplevel #0 $::mallocopts(-cleanup)] msg } } unset ::mallocopts } @@ -357,14 +357,19 @@ 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; + } -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 { @@ -392,26 +397,97 @@ 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