From 9a30cf653fd1cd3527e14e341ccf6857a278a175 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Wed, 18 Jan 2006 04:26:07 +0000 Subject: [PATCH] Handle malloc() failures that occur inside create_collation() calls. (CVS 2966) FossilOrigin-Name: 95c5903f368413019af83aa73263e0e9d1204b62 --- manifest | 16 +++--- manifest.uuid | 2 +- src/main.c | 131 +++++++++++++++++++++++++++-------------------- src/test1.c | 17 ++++-- test/malloc.test | 61 +++++++++++++++------- 5 files changed, 141 insertions(+), 86 deletions(-) diff --git a/manifest b/manifest index f3f3576643..6cc0214f49 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Arrange\sfor\sThreadData\sto\sbe\sautomatically\sdeallocated\seven\sif\sSQLITE_MEMDEBUG\sis\sdefined.\sFix\sfor\s#1623.\s(CVS\s2965) -D 2006-01-17T16:10:14 +C Handle\smalloc()\sfailures\sthat\soccur\sinside\screate_collation()\scalls.\s(CVS\s2966) +D 2006-01-18T04:26:07 F Makefile.in ab3ffd8d469cef4477257169b82810030a6bb967 F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -48,7 +48,7 @@ F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/insert.c a5595cf8d1d8ba087b676a63f1f7277ea44b5ac1 F src/legacy.c 9bf7ee1b63c99aac6669533986a5240b16101458 -F src/main.c e934ce6ce3b7166ad98c2778160f865761196480 +F src/main.c bab16cf13d9a6388c321f6bc4693d258aea80a2a F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/os.c 1d1a61cdf150e9f9520a3bc787c8465148ea2e78 F src/os.h 9debc3d3ca4cdafde222a0ea74a4c8415aef4f22 @@ -73,7 +73,7 @@ F src/sqlite.h.in 492580f7e3ff71eb43193eb7bb98e2d549889ce3 F src/sqliteInt.h d7b20e0a9453db123809d0bcc46d6ae0e4cf6bca F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316 F src/tclsqlite.c d650bea0248fc0a310ddc2cb94273a3a5021fddf -F src/test1.c 4dccd51f786f24d8f947f1028d840ab35f46d4de +F src/test1.c deb48cd5ab369a2ffccb62b017d248188a3be201 F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b F src/test3.c 9742aa146eb750cab81c1d5605286c3a0eb88054 F src/test4.c 6633cb7b4a7429e938804a34f688d118c8b7f8e1 @@ -186,7 +186,7 @@ F test/lock.test 9b7afcb24f53d24da502abb33daaad2cd6d44107 F test/lock2.test d83ba79d3c4fffdb5b926c7d8ca7a36c34288a55 F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9 F test/main.test b12f01d49a5c805a33fa6c0ef168691f63056e79 -F test/malloc.test 34c2c0ce7f45bc5fe2f7f3c0b911e505af66e27f +F test/malloc.test 095d23a3840549cfc4282f95d9dc531152473c05 F test/malloc2.test e6e321db96d6c94cb18bf82ad7215070c41e624e F test/malloc3.test 265644c655497242f7c0a1bb5b36c8500a5fc27c F test/malloc4.test 2e29d155eb4b4808019ef47eeedfcbe9e09e0f05 @@ -341,7 +341,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 62dd2427784721436737a6e8e11fc05e10f0c44d -R 394c8b76a3f1fd5dd680d2c15b203185 +P 9e2e40845d30cc150abe23ee318a721b4fe9613c +R 07ad42513a6cd0f560889373df73f012 U danielk1977 -Z 4cce626803e4e936d7ee616c54ded64d +Z 7bf4533c1b6879283691c3482fcc8f38 diff --git a/manifest.uuid b/manifest.uuid index cfa639532d..608f979656 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9e2e40845d30cc150abe23ee318a721b4fe9613c \ No newline at end of file +95c5903f368413019af83aa73263e0e9d1204b62 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 6ceea4b44a..59e524a3dc 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.324 2006/01/17 13:21:40 danielk1977 Exp $ +** $Id: main.c,v 1.325 2006/01/18 04:26:07 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -745,6 +745,60 @@ int sqlite3_errcode(sqlite3 *db){ return db->errCode; } +static int createCollation( + sqlite3* db, + const char *zName, + int enc, + void* pCtx, + int(*xCompare)(void*,int,const void*,int,const void*) +){ + CollSeq *pColl; + + if( sqlite3SafetyCheck(db) ){ + return SQLITE_MISUSE; + } + + /* If SQLITE_UTF16 is specified as the encoding type, transform this + ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the + ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. + */ + if( enc==SQLITE_UTF16 ){ + enc = SQLITE_UTF16NATIVE; + } + + if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){ + sqlite3Error(db, SQLITE_ERROR, + "Param 3 to sqlite3_create_collation() must be one of " + "SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE" + ); + return SQLITE_ERROR; + } + + /* Check if this call is removing or replacing an existing collation + ** sequence. If so, and there are active VMs, return busy. If there + ** are no active VMs, invalidate any pre-compiled statements. + */ + pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0); + if( pColl && pColl->xCmp ){ + if( db->activeVdbeCnt ){ + sqlite3Error(db, SQLITE_BUSY, + "Unable to delete/modify collation sequence due to active statements"); + return SQLITE_BUSY; + } + sqlite3ExpirePreparedStatements(db); + } + + pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1); + if( pColl ){ + pColl->xCmp = xCompare; + pColl->pUser = pCtx; + pColl->enc = enc; + } + sqlite3Error(db, SQLITE_OK, 0); + return SQLITE_OK; +} + + /* ** This routine does the work of opening a database on behalf of ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" @@ -776,8 +830,8 @@ static int openDatabase( ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. */ - if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) || - sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) || + if( createCollation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) || + createCollation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) || (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0 ){ /* sqlite3_create_collation() is an external API. So the mallocFailed flag @@ -789,7 +843,7 @@ static int openDatabase( } /* Also add a UTF-8 case-insensitive collation sequence. */ - sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc); + createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc); /* Set flags on the built-in collating sequences */ db->pDfltColl->type = SQLITE_COLL_BINARY; @@ -935,52 +989,14 @@ int sqlite3_create_collation( void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ - CollSeq *pColl; - int rc = SQLITE_OK; - - if( sqlite3SafetyCheck(db) ){ - return SQLITE_MISUSE; - } - - /* If SQLITE_UTF16 is specified as the encoding type, transform this - ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the - ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. - */ - if( enc==SQLITE_UTF16 ){ - enc = SQLITE_UTF16NATIVE; - } - - if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){ - sqlite3Error(db, SQLITE_ERROR, - "Param 3 to sqlite3_create_collation() must be one of " - "SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE" - ); - return SQLITE_ERROR; - } - - /* Check if this call is removing or replacing an existing collation - ** sequence. If so, and there are active VMs, return busy. If there - ** are no active VMs, invalidate any pre-compiled statements. - */ - pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0); - if( pColl && pColl->xCmp ){ - if( db->activeVdbeCnt ){ - sqlite3Error(db, SQLITE_BUSY, - "Unable to delete/modify collation sequence due to active statements"); - return SQLITE_BUSY; - } - sqlite3ExpirePreparedStatements(db); - } - - pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1); - if( 0==pColl ){ + int rc; + assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); + rc = createCollation(db, zName, enc, pCtx, xCompare); + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + sqlite3MallocClearFailed(); rc = SQLITE_NOMEM; - }else{ - pColl->xCmp = xCompare; - pColl->pUser = pCtx; - pColl->enc = enc; + sqlite3Error(db, rc, 0); } - sqlite3Error(db, rc, 0); return rc; } @@ -995,14 +1011,19 @@ int sqlite3_create_collation16( void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ - char *zName8; - int rc; - if( sqlite3SafetyCheck(db) ){ - return SQLITE_MISUSE; - } + int rc = SQLITE_OK; + char *zName8; + assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); zName8 = sqlite3utf16to8(zName, -1); - rc = sqlite3_create_collation(db, zName8, enc, pCtx, xCompare); - sqliteFree(zName8); + if( zName8 ){ + rc = createCollation(db, zName8, enc, pCtx, xCompare); + sqliteFree(zName8); + } + if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + sqlite3MallocClearFailed(); + rc = SQLITE_NOMEM; + sqlite3Error(db, rc, 0); + } return rc; } #endif /* SQLITE_OMIT_UTF16 */ diff --git a/src/test1.c b/src/test1.c index 2d6f2727ea..d211ee39ee 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.193 2006/01/17 13:21:40 danielk1977 Exp $ +** $Id: test1.c,v 1.194 2006/01/18 04:26:07 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -1346,13 +1346,24 @@ static int test_collate( (void *)SQLITE_UTF16LE, val?test_collate_func:0); if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR; +#ifdef SQLITE_MEMDEBUG + if( sqlite3_iMallocFail>0 ){ + sqlite3_iMallocFail++; + } +#endif pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC); - sqlite3_create_collation16(db, sqlite3ValueText(pVal, SQLITE_UTF16NATIVE), - SQLITE_UTF16BE, (void *)SQLITE_UTF16BE, val?test_collate_func:0); + rc = sqlite3_create_collation16(db, + sqlite3ValueText(pVal, SQLITE_UTF16NATIVE), SQLITE_UTF16BE, + (void *)SQLITE_UTF16BE, val?test_collate_func:0); sqlite3ValueFree(pVal); } if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; + + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0); + return TCL_ERROR; + } return TCL_OK; bad_args: diff --git a/test/malloc.test b/test/malloc.test index 726bc3297b..ff934911f9 100644 --- a/test/malloc.test +++ b/test/malloc.test @@ -14,7 +14,7 @@ # 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.27 2006/01/17 13:21:40 danielk1977 Exp $ +# $Id: malloc.test,v 1.28 2006/01/18 04:26:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -97,7 +97,11 @@ proc do_malloc_test {tn args} { if {$leftover>0} { if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} set ::go 0 - set v {1 1} + if {$v} { + puts "\nError message returned: $msg" + } else { + set v {1 1} + } } else { set v2 [expr {$msg=="" || $msg=="out of memory"}] if {!$v2} {puts "\nError message returned: $msg"} @@ -363,25 +367,44 @@ ifcapable crashtest { } if {$tcl_platform(platform)!="windows"} { -do_malloc_test 14 -tclprep { - catch {db close} - sqlite3 db2 test2.db - db2 eval { - PRAGMA synchronous = 0; - CREATE TABLE t1(a, b); - INSERT INTO t1 VALUES(1, 2); - BEGIN; - INSERT INTO t1 VALUES(3, 4); + do_malloc_test 14 -tclprep { + catch {db close} + sqlite3 db2 test2.db + db2 eval { + PRAGMA synchronous = 0; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + BEGIN; + INSERT INTO t1 VALUES(3, 4); + } + copy_file test2.db test.db + copy_file test2.db-journal test.db-journal + db2 close + } -tclbody { + sqlite3 db test.db + db eval { + SELECT * FROM t1; + } } - copy_file test2.db test.db - copy_file test2.db-journal test.db-journal - db2 close -} -tclbody { - sqlite3 db test.db - db eval { - SELECT * FROM t1; - } } + +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. -- 2.39.5