Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Handle malloc() failures that occur inside create_collation() calls. (CVS 2966) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
95c5903f368413019af83aa73263e0e9 |
User & Date: | danielk1977 2006-01-18 04:26:07.000 |
Context
2006-01-18
| ||
05:51 | Handle malloc() failures that occur in open16() and errmsg16(). (CVS 2967) (check-in: 86eab9e53d user: danielk1977 tags: trunk) | |
04:26 | Handle malloc() failures that occur inside create_collation() calls. (CVS 2966) (check-in: 95c5903f36 user: danielk1977 tags: trunk) | |
2006-01-17
| ||
16:10 | Arrange for ThreadData to be automatically deallocated even if SQLITE_MEMDEBUG is defined. Fix for #1623. (CVS 2965) (check-in: 9e2e40845d user: danielk1977 tags: trunk) | |
Changes
Changes to src/main.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** 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. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** 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 |
︙ | ︙ | |||
740 741 742 743 744 745 746 747 748 749 750 751 752 753 | return SQLITE_NOMEM; } if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } return db->errCode; } /* ** This routine does the work of opening a database on behalf of ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" ** is UTF-8 encoded. */ static int openDatabase( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 | return SQLITE_NOMEM; } if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } 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" ** is UTF-8 encoded. */ static int openDatabase( |
︙ | ︙ | |||
772 773 774 775 776 777 778 | sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** 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. */ | | | | | 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 | sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** 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( 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 ** will have been cleared before returning. So set it explicitly here. */ sqlite3ThreadData()->mallocFailed = 1; db->magic = SQLITE_MAGIC_CLOSED; goto opendb_out; } /* Also add a UTF-8 case-insensitive collation sequence. */ createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc); /* Set flags on the built-in collating sequences */ db->pDfltColl->type = SQLITE_COLL_BINARY; pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "NOCASE", 6, 0); if( pColl ){ pColl->type = SQLITE_COLL_NOCASE; } |
︙ | ︙ | |||
931 932 933 934 935 936 937 | int sqlite3_create_collation( sqlite3* db, const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ | < | | < < < | < < < < < < < | < | < < < | < < < < < < < < < | < < | < < < < < < < < < < < < > | < | < < > | | > > > > > > | 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 | int sqlite3_create_collation( sqlite3* db, const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ int rc; assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); rc = createCollation(db, zName, enc, pCtx, xCompare); if( sqlite3ThreadDataReadOnly()->mallocFailed ){ sqlite3MallocClearFailed(); rc = SQLITE_NOMEM; sqlite3Error(db, rc, 0); } return rc; } #ifndef SQLITE_OMIT_UTF16 /* ** Register a new collation sequence with the database handle db. */ int sqlite3_create_collation16( sqlite3* db, const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ int rc = SQLITE_OK; char *zName8; assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); zName8 = sqlite3utf16to8(zName, -1); 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 */ /* ** Register a collation sequence factory callback with the database handle ** db. Replace any previously installed collation sequence factory. |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** 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. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** 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> |
︙ | ︙ | |||
1342 1343 1344 1345 1346 1347 1348 1349 1350 | (void *)SQLITE_UTF8, val?test_collate_func:0); if( rc==SQLITE_OK ){ if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR; rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE, (void *)SQLITE_UTF16LE, val?test_collate_func:0); if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR; pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC); | > > > > > > | | > > > > > | 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 | (void *)SQLITE_UTF8, val?test_collate_func:0); if( rc==SQLITE_OK ){ if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR; rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE, (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); 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: Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0); return TCL_ERROR; } |
︙ | ︙ |
Changes to test/malloc.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # 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. # | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #*********************************************************************** # 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]==""} { |
︙ | ︙ | |||
93 94 95 96 97 98 99 | } set v [catch $::mallocbody msg] set leftover [lindex [sqlite_malloc_stat] 2] if {$leftover>0} { if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} set ::go 0 | > > > | > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | } set v [catch $::mallocbody msg] set leftover [lindex [sqlite_malloc_stat] 2] if {$leftover>0} { if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} set ::go 0 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"} lappend v $v2 } } {1 1} |
︙ | ︙ | |||
359 360 361 362 363 364 365 | ATTACH 'test2.db' as aux; SELECT * FROM t1; SELECT * FROM t2; } } if {$tcl_platform(platform)!="windows"} { | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 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 | 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 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; } } } 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 |