-C Disable\stests\sin\smisc7\sthat\sdo\snot\swork\son\swindows\sdue\sto\slimitations\sof\nthe\swindows\sfile\ssystem.\s(CVS\s3873)
-D 2007-04-25T15:42:26
+C Fix\ssegfaults\sthat\scan\soccur\sif\sa\smalloc\sfailure\shappens\sjust\sbefore\na\sbuilt-in\sfunction\scalls\ssqlite3_value_text().\s(CVS\s3874)
+D 2007-04-25T18:23:53
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/build.c 1880da163d9aa404016242b8b76d69907f682cd8
F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
-F src/date.c 74b76691bddf58b634f6bf4a77c8c58234268c6e
+F src/date.c 94a6777df13d2aaacd19de080d9e8d3444364133
F src/delete.c 5c0d89b3ef7d48fe1f5124bfe8341f982747fe29
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
F src/expr.c 2f0f9f89efe9170e5e6ca5d5e93a9d5896fff5ac
-F src/func.c 007d957c057bb42b0d37aa6ad4be0e1c67a8871b
+F src/func.c acb2c5055629ae3eebd71868af10fe425ef05f06
F src/hash.c 67b23e14f0257b69a3e8aa663e4eeadc1a2b6fd5
F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
F src/insert.c 413cc06990cb3c401e64e596776c1e43934f8841
F src/vdbe.c 814dab208a156250bc5e77f827f4e0c8ad734820
F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
F src/vdbeInt.h 4b19fd8febad3fd14c4c97adaefc06754d323132
-F src/vdbeapi.c 1fca7ff056d03f131caa6b1296bb221da65ed7f4
+F src/vdbeapi.c 245263aa2d70d87b1201753cddc881996f219843
F src/vdbeaux.c ef59545f53f90394283f2fd003375d3ebbf0bd6e
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
F src/vdbemem.c 981a113405bd9b80aeb71fe246a2f01708e8a8f7
F test/malloc5.test f228cb7101ae403327824d327a1f5651d83ef0f2
F test/malloc6.test 025ae0b78542e0ddd000d23f79d93e9be9ba0f15
F test/malloc7.test 1cf52834509eac7ebeb92105dacd4669f9ca9869
+F test/malloc8.test ede3231e1d9359b3c618357e49cb1c62267382e7
F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8
F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 16979f4525652bfd6c6e5306eafc883bef3880aa
-R 28b0457dabf779eb2bc14720d6227390
+P 66646d6fda067e19240808aef65fafd8fa177cdd
+R 48b7346bd8cf5e77d4009859f7c6c683
U drh
-Z 15c285b6aa265216fe50f5053ca77b43
+Z fd08492b87e717e5d32a8be7d387293c
-66646d6fda067e19240808aef65fafd8fa177cdd
\ No newline at end of file
+9cb0ed6ee9827bc6884a0195044d5b6ad0de698e
\ No newline at end of file
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: date.c,v 1.62 2007/04/06 02:32:34 drh Exp $
+** $Id: date.c,v 1.63 2007/04/25 18:23:53 drh Exp $
**
** NOTES:
**
*/
static int isDate(int argc, sqlite3_value **argv, DateTime *p){
int i;
+ const unsigned char *z;
if( argc==0 ) return 1;
- if( SQLITE_NULL==sqlite3_value_type(argv[0]) ||
- parseDateOrTime((char*)sqlite3_value_text(argv[0]), p) ) return 1;
+ if( (z = sqlite3_value_text(argv[0]))==0 || parseDateOrTime((char*)z, p) ){
+ return 1;
+ }
for(i=1; i<argc; i++){
- if( SQLITE_NULL==sqlite3_value_type(argv[i]) ||
- parseModifier((char*)sqlite3_value_text(argv[i]), p) ) return 1;
+ if( (z = sqlite3_value_text(argv[i]))==0 || parseModifier((char*)z, p) ){
+ return 1;
+ }
}
return 0;
}
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: func.c,v 1.139 2007/04/10 13:51:18 drh Exp $
+** $Id: func.c,v 1.140 2007/04/25 18:23:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
}
case SQLITE_TEXT: {
const unsigned char *z = sqlite3_value_text(argv[0]);
+ if( z==0 ) return;
for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; }
sqlite3_result_int(context, len);
break;
** Implementation of the upper() and lower() SQL functions.
*/
static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- unsigned char *z;
+ char *z1;
+ const char *z2;
int i;
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
- z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
- if( z==0 ) return;
- strcpy((char*)z, (char*)sqlite3_value_text(argv[0]));
- for(i=0; z[i]; i++){
- z[i] = toupper(z[i]);
+ z2 = (char*)sqlite3_value_text(argv[0]);
+ if( z2 ){
+ z1 = sqlite3_malloc(sqlite3_value_bytes(argv[0])+1);
+ if( z1 ){
+ strcpy(z1, z2);
+ for(i=0; z1[i]; i++){
+ z1[i] = toupper(z1[i]);
+ }
+ sqlite3_result_text(context, z1, -1, sqlite3_free);
+ }
}
- sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT);
- sqliteFree(z);
}
static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- unsigned char *z;
+ char *z1;
+ const char *z2;
int i;
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
- z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
- if( z==0 ) return;
- strcpy((char*)z, (char*)sqlite3_value_text(argv[0]));
- for(i=0; z[i]; i++){
- z[i] = tolower(z[i]);
+ z2 = (char*)sqlite3_value_text(argv[0]);
+ if( z2 ){
+ z1 = sqlite3_malloc(sqlite3_value_bytes(argv[0])+1);
+ if( z1 ){
+ strcpy(z1, z2);
+ for(i=0; z1[i]; i++){
+ z1[i] = tolower(z1[i]);
+ }
+ sqlite3_result_text(context, z1, -1, sqlite3_free);
+ }
}
- sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT);
- sqliteFree(z);
}
/*
** Otherwise, return an error.
*/
const unsigned char *zEsc = sqlite3_value_text(argv[2]);
+ if( zEsc==0 ) return;
if( sqlite3utf8CharLen((char*)zEsc, -1)!=1 ){
sqlite3_result_error(context,
"ESCAPE expression must be a single character", -1);
const unsigned char *zArg = sqlite3_value_text(argv[0]);
char *z;
+ if( zArg==0 ) return;
for(i=n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
z = sqliteMalloc( i+n+3 );
if( z==0 ) return;
int i, j; /* Loop counters */
assert( argc==3 );
- if( sqlite3_value_type(argv[0])==SQLITE_NULL ||
- sqlite3_value_type(argv[1])==SQLITE_NULL ||
- sqlite3_value_type(argv[2])==SQLITE_NULL ){
- return;
- }
zStr = sqlite3_value_text(argv[0]);
+ if( zStr==0 ) return;
nStr = sqlite3_value_bytes(argv[0]);
zPattern = sqlite3_value_text(argv[1]);
+ if( zPattern==0 ) return;
nPattern = sqlite3_value_bytes(argv[1]);
zRep = sqlite3_value_text(argv[2]);
+ if( zRep==0 ) return;
nRep = sqlite3_value_bytes(argv[2]);
if( nPattern>=nRep ){
nOut = nStr;
return;
}
zIn = sqlite3_value_text(argv[0]);
+ if( zIn==0 ) return;
nIn = sqlite3_value_bytes(argv[0]);
if( argc==1 ){
static const unsigned char zSpace[] = " ";
zCharSet = zSpace;
- }else if( sqlite3_value_type(argv[1])==SQLITE_NULL ){
+ }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){
return;
- }else{
- zCharSet = sqlite3_value_text(argv[1]);
}
cFirst = zCharSet[0];
if( cFirst ){
*/
static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
const char *zFile = (const char *)sqlite3_value_text(argv[0]);
- const char *zProc = 0;
+ const char *zProc;
sqlite3 *db = sqlite3_user_data(context);
char *zErrMsg = 0;
if( argc==2 ){
zProc = (const char *)sqlite3_value_text(argv[1]);
+ }else{
+ zProc = 0;
}
- if( sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){
+ if( zFile && sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){
sqlite3_result_error(context, zErrMsg, -1);
sqlite3_free(zErrMsg);
}
Vdbe *pVm = (Vdbe *)pStmt;
int vals = sqlite3_data_count(pStmt);
if( i>=vals || i<0 ){
- static const Mem nullMem = {{0}, 0.0, "", 0, MEM_Null, MEM_Null };
+ static const Mem nullMem = {{0}, 0.0, "", 0, MEM_Null, SQLITE_NULL };
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
return (Mem*)&nullMem;
}
--- /dev/null
+# 2006 July 26
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file contains additional out-of-memory checks (see malloc.tcl)
+# added to expose a bug in out-of-memory handling for sqlite3_value_text()
+#
+# $Id: malloc8.test,v 1.1 2007/04/25 18:23:53 drh 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]==""} {
+ puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
+ finish_test
+ return
+}
+
+# Usage: do_malloc_test <test number> <options...>
+#
+# The first argument, <test number>, is an integer used to name the
+# tests executed by this proc. Options are as follows:
+#
+# -tclprep TCL script to run to prepare test.
+# -sqlprep SQL script to run to prepare test.
+# -tclbody TCL script to run with malloc failure simulation.
+# -sqlbody TCL script to run with malloc failure simulation.
+# -cleanup TCL script to run after the test.
+#
+# This command runs a series of tests to verify SQLite's ability
+# to handle an out-of-memory condition gracefully. It is assumed
+# that if this condition occurs a malloc() call will return a
+# NULL pointer. Linux, for example, doesn't do that by default. See
+# the "BUGS" section of malloc(3).
+#
+# Each iteration of a loop, the TCL commands in any argument passed
+# to the -tclbody switch, followed by the SQL commands in any argument
+# passed to the -sqlbody switch are executed. Each iteration the
+# Nth call to sqliteMalloc() is made to fail, where N is increased
+# each time the loop runs starting from 1. When all commands execute
+# successfully, the loop ends.
+#
+proc do_malloc_test {tn args} {
+ array unset ::mallocopts
+ array set ::mallocopts $args
+
+ set ::go 1
+ for {set ::n 1} {$::go && $::n < 50000} {incr ::n} {
+ do_test malloc8-$tn.$::n {
+
+ sqlite_malloc_fail 0
+ catch {db close}
+ sqlite3 db test.db
+ set ::DB [sqlite3_connection_pointer db]
+
+ # Execute any -tclprep and -sqlprep scripts.
+ #
+ if {[info exists ::mallocopts(-tclprep)]} {
+ eval $::mallocopts(-tclprep)
+ }
+ if {[info exists ::mallocopts(-sqlprep)]} {
+ execsql $::mallocopts(-sqlprep)
+ }
+
+ # Now set the ${::n}th malloc() to fail and execute the -tclbody and
+ # -sqlbody scripts.
+ #
+ sqlite_malloc_fail $::n
+ set ::mallocbody {}
+ if {[info exists ::mallocopts(-tclbody)]} {
+ append ::mallocbody "$::mallocopts(-tclbody)\n"
+ }
+ if {[info exists ::mallocopts(-sqlbody)]} {
+ append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
+ }
+ set v [catch $::mallocbody msg]
+
+ # If the test fails (if $v!=0) and the database connection actually
+ # exists, make sure the failure code is SQLITE_NOMEM.
+ if {$v && [info command db]=="db" && [info exists ::mallocopts(-sqlbody)]
+ && [db errorcode]!=7} {
+ set v 999
+ }
+
+ 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}
+
+ if {[info exists ::mallocopts(-cleanup)]} {
+ catch [list uplevel #0 $::mallocopts(-cleanup)] msg
+ }
+ }
+ unset ::mallocopts
+}
+
+# The setup is a database with UTF-16 encoding that contains a single
+# large string. We will be running lots of queries against this
+# database. Because we will be extracting the string as UTF-8, there
+# is a type conversion that occurs and thus an opportunity for malloc()
+# to fail and for sqlite3_value_text() to return 0 even though
+# sqlite3_value_type() returns SQLITE_TEXT.
+#
+db close
+file delete -force test.db test.db-journal
+sqlite3 db test.db
+db eval {
+ PRAGMA encoding='UTF-16';
+ CREATE TABLE t1(a);
+ INSERT INTO t1
+ VALUES('0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ');
+}
+
+
+do_malloc_test 1 -sqlbody {
+ SELECT lower(a), upper(a), quote(a), trim(a), trim('x',a) FROM t1;
+}
+do_malloc_test 2 -sqlbody {
+ SELECT replace(a,'x','y'), replace('x',a,'y'), replace('x','y',a)
+ FROM t1;
+}
+do_malloc_test 3 -sqlbody {
+ SELECT length(a), substr(a, 4, 4) FROM t1;
+}
+do_malloc_test 4 -sqlbody {
+ SELECT julianday(a,a) FROM t1;
+}
+do_malloc_test 5 -sqlbody {
+ SELECT 1 FROM t1 WHERE a LIKE 'hello' ESCAPE NULL;
+}
+
+# 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