]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add some extra tests for malloc failure during expression parsing and execution using...
authordanielk1977 <danielk1977@noemail.net>
Wed, 30 May 2007 10:36:47 +0000 (10:36 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Wed, 30 May 2007 10:36:47 +0000 (10:36 +0000)
FossilOrigin-Name: 7522d2fb3204d107b8b4816d7f39c88741f20230

13 files changed:
manifest
manifest.uuid
src/expr.c
src/parse.y
src/vdbeapi.c
test/fuzz.test
test/fuzz_common.tcl [new file with mode: 0644]
test/fuzz_malloc.test [new file with mode: 0644]
test/malloc.test
test/mallocB.test [new file with mode: 0644]
test/malloc_common.tcl [new file with mode: 0644]
test/quick.test
test/soak.test

index d2777c8b7d78f9f62b5d0e850ecf03d2f15b9cfd..b1cfab2c2c7d8e528d0b8beca7f9b460a964b789 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sstart\sof\sthe\ssoak-test\sinfrastructure.\s(CVS\s4042)
-D 2007-05-30T08:18:04
+C Add\ssome\sextra\stests\sfor\smalloc\sfailure\sduring\sexpression\sparsing\sand\sexecution\susing\sfuzzily\sgenerated\sSQL.\s(CVS\s4043)
+D 2007-05-30T10:36:47
 F Makefile.in a42354804b50c2708ce72cf79e4daa30f50191b5
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -71,7 +71,7 @@ F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
 F src/date.c 6049db7d5a8fdf2c677ff7d58fa31d4f6593c988
 F src/delete.c 5c0d89b3ef7d48fe1f5124bfe8341f982747fe29
 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
-F src/expr.c 7243b6c01b976662873bbba397640fb4cbed76bc
+F src/expr.c fb386ee80026e221869f49159c0963e851c184c9
 F src/func.c dfd0dd496dac46c2b14a88292cd9e141aae3ba63
 F src/hash.c 67b23e14f0257b69a3e8aa663e4eeadc1a2b6fd5
 F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
@@ -95,7 +95,7 @@ F src/os_win.c d868d5f9e95ec9c1b9e2a30c54c996053db6dddd
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
 F src/pager.c a193f8f0783e33ea0aa1965e951c3daa2b2c9c4e
 F src/pager.h 94110a5570dca30d54a883e880a3633b2e4c05ae
-F src/parse.y e276a0c35d6579938708f0842d0eba4e9b6866e6
+F src/parse.y e3d8e3f748bd3915523f77f704f303c7f0de613b
 F src/pragma.c 0d25dad58bdfd6789943a10f1b9663c2eb85b96d
 F src/prepare.c 87c23644986b5e41a58bc76f05abebd899e00089
 F src/printf.c cd91e057fa7e2661673eecd4eeecf4900b1e5cfe
@@ -136,7 +136,7 @@ F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
 F src/vdbe.c 74a82e8dc0cd84416fcca63d158c5ab8715f158d
 F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
 F src/vdbeInt.h 7d2bf163d6d4e815724a457f2216dd8e38c3955c
-F src/vdbeapi.c f89d6bc5264e66f44589e454fbeeee96854d0dd3
+F src/vdbeapi.c 3747e4c3bc3139ff688bb3df462b10e42c084d16
 F src/vdbeaux.c a978d170b2ca99c8ff3da8a91f116a66da2600ac
 F src/vdbeblob.c 96f3572fdc45eda5be06e6372b612bc30742d9f0
 F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
@@ -250,8 +250,10 @@ F test/fts2l.test 4c53c89ce3919003765ff4fd8d98ecf724d97dd3
 F test/fts2m.test 4b30142ead6f3ed076e880a2a464064c5ad58c51
 F test/fts2n.test a70357e72742681eaebfdbe9007b87ff3b771638
 F test/func.test 605989453d1b42cec1d05c17aa232dc98e3e04e6
-F test/fuzz.test 9fdb668167bd38eb7137d49c8e9c250994bdbd5b
+F test/fuzz.test 62fc19dd36a427777fd671b569df07166548628a
 F test/fuzz2.test ea38692ce2da99ad79fe0be5eb1a452c1c4d37bb
+F test/fuzz_common.tcl ff4bc2dfc465f6878f8e2d819620914365382731
+F test/fuzz_malloc.test 41ef1135f2c319b4963b1524f1bdd4a3553b827d
 F test/hook.test 7e7645fd9a033f79cce8fdff151e32715e7ec50a
 F test/icu.test e6bfae7f625c88fd14df6f540fe835bdfc1e4329
 F test/in.test 369cb2aa1eab02296b4ec470732fe8c131260b1d
@@ -289,7 +291,7 @@ F test/lock2.test b95915eb4b6f8420acb30c68170d8f0ed9364efe
 F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9
 F test/lock4.test 49e22396b9be6e047b3d35469f233be79153c9d5
 F test/main.test e7212ce1023957c7209778cc87fa932bd79ba89a
-F test/malloc.test c468c018eecba78d1832cb9aaa23a7f824f07179
+F test/malloc.test 45a81af6328381d0630ab0a3d8cb8c58551603f7
 F test/malloc2.test 4ed7d719542c4570dec9c2ebe2bbdf3a9f3b0d05
 F test/malloc3.test e965954b6f808876a63d3101fd70370320b509a7
 F test/malloc4.test 59cd02f71b363302a04c4e77b97c0a1572eaa210
@@ -299,6 +301,8 @@ F test/malloc7.test 1cf52834509eac7ebeb92105dacd4669f9ca9869
 F test/malloc8.test e4054ca2a87ab1d42255bec009b177ba20b5a487
 F test/malloc9.test 8381041fd89c31fba60c8a1a1c776bb022108572
 F test/mallocA.test 525674e6e0775a9bf85a33f1da1c6bbddc712c30
+F test/mallocB.test 5a96951a5f06cfdbd48d61ac3add8aa77461b812
+F test/malloc_common.tcl 3cda97d63fbf370061ffa9795a24e5027367fef3
 F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8
 F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893
 F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
@@ -322,7 +326,7 @@ F test/pragma.test b0e73879206934a835856a8b8c4cc884cd8562f3
 F test/printf.test 69d8cb0771a1a5e4d9d5dece12fc2c16179ac5e5
 F test/progress.test 8b22b4974b0a95272566385f8cb8c341c7130df8 x
 F test/ptrchng.test 1c712dd6516e1377471744fa765e41c79a357da6
-F test/quick.test 41052ccf861fa49145496c9e9db62df4b0a2b6b8
+F test/quick.test 73a81a29fc28661c9c3fee2dcc3ded83cb1f1834
 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
 F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0
 F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
@@ -343,7 +347,7 @@ F test/shared.test 5c39f216ce85d723eda5875804bbf5ef8a03fcfc
 F test/shared2.test 8b48f8d33494413ef4cf250110d89403e2bf6b23
 F test/shared3.test 01e3e124dbb3859788aabc7cfb82f7ea04421749
 F test/shared_err.test cc528f6e78665787e93d9ce3a782a2ce5179d821
-F test/soak.test dac7ec07bdedd8f924de69ba029ed1dacbc1082a
+F test/soak.test 64f9b27fbcdec43335a88c546ce1983e6ba40d7b
 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
 F test/speed1.test 22e1b27af0683ed44dcd2f93ed817a9c3e65084a
 F test/speed2.test 53177056baf6556dcbdcf032bbdfc41c1aa74ded
@@ -496,7 +500,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 03750a2a6b5186689f7db6650c0a889429790b03
-R cd63e6e2215c48b174d5e94a02b48d9a
+P 5d0b247ca1667f5d773bda337cb6f58c3b14676a
+R a618a8ac57ff1c991566b3aa8912d34a
 U danielk1977
-Z 17f10a57e39853a2feb0d4c1a0988d68
+Z 5fc3b63bae0e892acacf6621f7949f54
index 8ba82a6c2204c9646ba883d779e95c79375d4c12..05930628fc1508a517a16b9363074f92ee9de87e 100644 (file)
@@ -1 +1 @@
-5d0b247ca1667f5d773bda337cb6f58c3b14676a
\ No newline at end of file
+7522d2fb3204d107b8b4816d7f39c88741f20230
\ No newline at end of file
index c4f395bf8c9bd932a9e9373c6e395489a1ba7920..a6c53ee2133eee65ef1944a087f3647deec6acd4 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.295 2007/05/29 12:11:30 danielk1977 Exp $
+** $Id: expr.c,v 1.296 2007/05/30 10:36:47 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1627,13 +1627,16 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
 ** text z[0..n-1] on the stack.
 */
 static void codeInteger(Vdbe *v, const char *z, int n){
-  int i;
-  if( sqlite3GetInt32(z, &i) ){
-    sqlite3VdbeAddOp(v, OP_Integer, i, 0);
-  }else if( sqlite3FitsIn64Bits(z) ){
-    sqlite3VdbeOp3(v, OP_Int64, 0, 0, z, n);
-  }else{
-    sqlite3VdbeOp3(v, OP_Real, 0, 0, z, n);
+  assert( z || sqlite3MallocFailed() );
+  if( z ){
+    int i;
+    if( sqlite3GetInt32(z, &i) ){
+      sqlite3VdbeAddOp(v, OP_Integer, i, 0);
+    }else if( sqlite3FitsIn64Bits(z) ){
+      sqlite3VdbeOp3(v, OP_Int64, 0, 0, z, n);
+    }else{
+      sqlite3VdbeOp3(v, OP_Real, 0, 0, z, n);
+    }
   }
 }
 
index e78993648fd554f5179bff6bd341c8e98e4a058d..1fc890bfd837d0fc431455097a6838810b27bd05 100644 (file)
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.228 2007/05/15 16:51:37 drh Exp $
+** @(#) $Id: parse.y,v 1.229 2007/05/30 10:36:47 danielk1977 Exp $
 */
 
 // All token codes are small integers with #defines that begin with "TK_"
@@ -659,7 +659,7 @@ expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
 }
 %endif  SQLITE_OMIT_CAST
 expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
-  if( Y->nExpr>SQLITE_MAX_FUNCTION_ARG ){
+  if( Y && Y->nExpr>SQLITE_MAX_FUNCTION_ARG ){
     sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
   }
   A = sqlite3ExprFunction(Y, &X);
index e841a626e15debf3e2c710ec4b9596f80fbc69a6..63c3254ede84d0951b0273b6112e345373367472 100644 (file)
@@ -498,6 +498,11 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
 const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
   const void *val;
   val = sqlite3_value_blob( columnMem(pStmt,i) );
+  /* Even though there is no encoding conversion, value_blob() might
+  ** need to call malloc() to expand the result of a zeroblob() 
+  ** expression. 
+  */
+  columnMallocFailure(pStmt);
   return val;
 }
 int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
index 6f313a8738a70725f0aa901f0fdc761325bb7671..76e3aad90deea4cc5145446de389fced232fc7e5 100644 (file)
@@ -19,7 +19,7 @@
 #
 # The most complicated trees are for SELECT statements.
 #
-# $Id: fuzz.test,v 1.13 2007/05/30 08:18:04 danielk1977 Exp $
+# $Id: fuzz.test,v 1.14 2007/05/30 10:36:47 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -31,384 +31,7 @@ if {[info exists ::ISQUICK]} {
   if {$::ISQUICK} { set ::REPEATS 20 }
 }
 
-proc fuzz {TemplateList} {
-  set n [llength $TemplateList]
-  set i [expr {int(rand()*$n)}]
-  set r [uplevel 1 subst -novar [list [lindex $TemplateList $i]]]
-
-  string map {"\n" " "} $r
-}
-
-# Fuzzy generation primitives:
-#
-#     Literal
-#     UnaryOp
-#     BinaryOp
-#     Expr
-#     Table
-#     Select
-#     Insert
-#
-
-# Returns a string representing an SQL literal.
-#
-proc Literal {} {
-  set TemplateList {
-    456 0 -456 1 -1 
-    2147483648 2147483647 2147483649 -2147483647 -2147483648 -2147483649
-    'The' 'first' 'experiments' 'in' 'hardware' 'fault' 'injection'
-    zeroblob(1000)
-    NULL
-    56.1 -56.1
-    123456789.1234567899
-  }
-  fuzz $TemplateList
-}
-
-# Returns a string containing an SQL unary operator (e.g. "+" or "NOT").
-#
-proc UnaryOp {} {
-  set TemplateList {+ - NOT ~}
-  fuzz $TemplateList
-}
-
-# Returns a string containing an SQL binary operator (e.g. "*" or "/").
-#
-proc BinaryOp {} {
-  set TemplateList {
-    || * / % + - << >> & | < <= > >= = == != <> AND OR
-    LIKE GLOB {NOT LIKE}
-  }
-  fuzz $TemplateList
-}
-
-# Return the complete text of an SQL expression.
-#
-set ::ExprDepth 0
-proc Expr { {c {}} } {
-  incr ::ExprDepth
-
-  set TemplateList [concat $c $c $c {[Literal]}]
-  if {$::ExprDepth < 3} {
-    lappend TemplateList \
-      {[Expr $c] [BinaryOp] [Expr $c]}                              \
-      {[UnaryOp] [Expr $c]}                                         \
-      {[Expr $c] ISNULL}                                            \
-      {[Expr $c] NOTNULL}                                           \
-      {CAST([Expr $c] AS blob)}                                     \
-      {CAST([Expr $c] AS text)}                                     \
-      {CAST([Expr $c] AS integer)}                                  \
-      {CAST([Expr $c] AS real)}                                     \
-      {abs([Expr])}                                                 \
-      {coalesce([Expr], [Expr])}                                    \
-      {hex([Expr])}                                                 \
-      {length([Expr])}                                              \
-      {lower([Expr])}                                               \
-      {upper([Expr])}                                               \
-      {quote([Expr])}                                               \
-      {random()}                                                    \
-      {randomblob(min(max([Expr],1), 500))}                         \
-      {typeof([Expr])}                                              \
-      {substr([Expr],[Expr],[Expr])}                                \
-      {CASE WHEN [Expr $c] THEN [Expr $c] ELSE [Expr $c] END}       \
-      {[Literal]} {[Literal]} {[Literal]}                           \
-      {[Literal]} {[Literal]} {[Literal]}                           \
-      {[Literal]} {[Literal]} {[Literal]}                           \
-      {[Literal]} {[Literal]} {[Literal]}
-  }
-  if {$::SelectDepth < 4} {
-    lappend TemplateList \
-      {([Select 1])}                       \
-      {[Expr $c] IN ([Select 1])}          \
-      {[Expr $c] NOT IN ([Select 1])}      \
-      {EXISTS ([Select 1])}                \
-  } 
-  set res [fuzz $TemplateList]
-  incr ::ExprDepth -1
-  return $res
-}
-
-# Return a valid table name.
-#
-set ::TableList [list]
-proc Table {} {
-  set TemplateList [concat sqlite_master $::TableList]
-  fuzz $TemplateList
-}
-
-# Return one of:
-#
-#     "SELECT DISTINCT", "SELECT ALL" or "SELECT"
-#
-proc SelectKw {} {
-  set TemplateList {
-    "SELECT DISTINCT"
-    "SELECT ALL"
-    "SELECT"
-  }
-  fuzz $TemplateList
-}
-
-# Return a result set for a SELECT statement.
-#
-proc ResultSet {{nRes 0} {c ""}} {
-  if {$nRes == 0} {
-    set nRes [expr {rand()*2 + 1}]
-  }
-
-  set aRes [list]
-  for {set ii 0} {$ii < $nRes} {incr ii} {
-    lappend aRes [Expr $c]
-  }
-
-  join $aRes ", "
-}
-
-set ::SelectDepth 0
-set ::ColumnList [list]
-proc SimpleSelect {{nRes 0}} {
-
-  set TemplateList {
-      {[SelectKw] [ResultSet $nRes]}
-  }
-
-  # The ::SelectDepth variable contains the number of ancestor SELECT
-  # statements (i.e. for a top level SELECT it is set to 0, for a
-  # sub-select 1, for a sub-select of a sub-select 2 etc.).
-  #
-  # If this is already greater than 3, do not generate a complicated
-  # SELECT statement. This tends to cause parser stack overflow (too
-  # boring to bother with).
-  #
-  if {$::SelectDepth < 4} {
-    lappend TemplateList \
-        {[SelectKw] [ResultSet $nRes $::ColumnList] FROM ([Select])}     \
-        {[SelectKw] [ResultSet $nRes] FROM ([Select])}                   \
-        {[SelectKw] [ResultSet $nRes $::ColumnList] FROM [Table]}        \
-        {
-             [SelectKw] [ResultSet $nRes $::ColumnList] 
-             FROM ([Select]) 
-             GROUP BY [Expr]
-             HAVING [Expr]
-        }                                                                \
-
-    if {0 == $nRes} {
-      lappend TemplateList                                               \
-          {[SelectKw] * FROM ([Select])}                                 \
-          {[SelectKw] * FROM [Table]}                                    \
-          {[SelectKw] * FROM [Table] WHERE [Expr $::ColumnList]}         \
-          {
-             [SelectKw] * 
-             FROM [Table],[Table] AS t2 
-             WHERE [Expr $::ColumnList] 
-          } {
-             [SelectKw] * 
-             FROM [Table] LEFT OUTER JOIN [Table] AS t2 
-             ON [Expr $::ColumnList]
-             WHERE [Expr $::ColumnList] 
-          }
-    }
-  } 
-
-  fuzz $TemplateList
-}
-
-# Return a SELECT statement.
-#
-# If boolean parameter $isExpr is set to true, make sure the
-# returned SELECT statement returns a single column of data.
-#
-proc Select {{nMulti 0}} {
-  set TemplateList {
-    {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} 
-    {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} 
-    {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} 
-    {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} 
-    {[SimpleSelect $nMulti] ORDER BY [Expr] DESC}
-    {[SimpleSelect $nMulti] ORDER BY [Expr] ASC}
-    {[SimpleSelect $nMulti] ORDER BY [Expr] ASC, [Expr] DESC}
-    {[SimpleSelect $nMulti] ORDER BY [Expr] LIMIT [Expr] OFFSET [Expr]}
-  }
-
-  if {$::SelectDepth < 4} {
-    if {$nMulti == 0} {
-      set nMulti [expr {(rand()*2)+1}]
-    }
-    lappend TemplateList                                             \
-        {[SimpleSelect $nMulti] UNION     [Select $nMulti]}          \
-        {[SimpleSelect $nMulti] UNION ALL [Select $nMulti]}          \
-        {[SimpleSelect $nMulti] EXCEPT    [Select $nMulti]}          \
-        {[SimpleSelect $nMulti] INTERSECT [Select $nMulti]}
-  }
-
-  incr ::SelectDepth
-  set res [fuzz $TemplateList]
-  incr ::SelectDepth -1
-  set res
-}
-
-# Generate and return a fuzzy INSERT statement.
-#
-proc Insert {} {
-  set TemplateList {
-      {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr]);}
-      {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr], [Expr]);}
-      {INSERT INTO [Table] VALUES([Expr], [Expr]);}
-  }
-  fuzz $TemplateList
-}
-
-proc Column {} {
-  fuzz $::ColumnList
-}
-
-# Generate and return a fuzzy UPDATE statement.
-#
-proc Update {} {
-  set TemplateList {
-    {UPDATE [Table] 
-     SET [Column] = [Expr $::ColumnList] 
-     WHERE [Expr $::ColumnList]}
-  }
-  fuzz $TemplateList
-}
-
-proc Delete {} {
-  set TemplateList {
-    {DELETE FROM [Table] WHERE [Expr $::ColumnList]}
-  }
-  fuzz $TemplateList
-}
-
-proc Statement {} {
-  set TemplateList {
-    {[Update]}
-    {[Insert]}
-    {[Select]}
-    {[Delete]}
-  }
-  fuzz $TemplateList
-}
-
-# Return an identifier. This just chooses randomly from a fixed set
-# of strings.
-proc Identifier {} {
-  set TemplateList {
-    This just chooses randomly a fixed 
-    We would also thank the developers 
-    for their analysis Samba
-  }
-  fuzz $TemplateList
-}
-
-proc Check {} {
-  # Use a large value for $::SelectDepth, because sub-selects are
-  # not allowed in expressions used by CHECK constraints.
-  #
-  set sd $::SelectDepth 
-  set ::SelectDepth 500
-  set TemplateList {
-    {}
-    {CHECK ([Expr])}
-  }
-  set res [fuzz $TemplateList]
-  set ::SelectDepth $sd
-  set res
-}
-
-proc Coltype {} {
-  set TemplateList {
-    {INTEGER PRIMARY KEY}
-    {VARCHAR [Check]}
-    {PRIMARY KEY}
-  }
-  fuzz $TemplateList
-}
-
-proc DropTable {} {
-  set TemplateList {
-    {DROP TABLE IF EXISTS [Identifier]}
-  }
-  fuzz $TemplateList
-}
-
-proc CreateView {} {
-  set TemplateList {
-    {CREATE VIEW [Identifier] AS [Select]}
-  }
-  fuzz $TemplateList
-}
-proc DropView {} {
-  set TemplateList {
-    {DROP VIEW IF EXISTS [Identifier]}
-  }
-  fuzz $TemplateList
-}
-
-proc CreateTable {} {
-  set TemplateList {
-    {CREATE TABLE [Identifier]([Identifier] [Coltype], [Identifier] [Coltype])}
-    {CREATE TEMP TABLE [Identifier]([Identifier] [Coltype])}
-  }
-  fuzz $TemplateList
-}
-
-proc CreateOrDropTableOrView {} {
-  set TemplateList {
-    {[CreateTable]}
-    {[DropTable]}
-    {[CreateView]}
-    {[DropView]}
-  }
-  fuzz $TemplateList
-}
-
-########################################################################
-
-set ::log [open fuzzy.log w]
-
-#
-# Usage: do_fuzzy_test <testname> ?<options>?
-# 
-#     -template
-#     -errorlist
-#     -repeats
-#     
-proc do_fuzzy_test {testname args} {
-  set ::fuzzyopts(-errorlist) [list]
-  set ::fuzzyopts(-repeats) $::REPEATS
-  array set ::fuzzyopts $args
-
-  lappend ::fuzzyopts(-errorlist) {parser stack overflow} 
-  lappend ::fuzzyopts(-errorlist) {ORDER BY}
-  lappend ::fuzzyopts(-errorlist) {GROUP BY}
-  lappend ::fuzzyopts(-errorlist) {datatype mismatch}
-
-  for {set ii 0} {$ii < $::fuzzyopts(-repeats)} {incr ii} {
-    do_test ${testname}.$ii {
-      set ::sql [subst $::fuzzyopts(-template)]
-      puts $::log $::sql
-      flush $::log
-      set rc [catch {execsql $::sql} msg]
-      set e 1
-      if {$rc} {
-        set e 0
-        foreach error $::fuzzyopts(-errorlist) {
-          if {0 == [string first $error $msg]} {
-            set e 1
-            break
-          }
-        }
-      }
-      if {$e == 0} {
-        puts ""
-        puts $::sql
-        puts $msg
-      }
-      set e
-    } {1}
-  }
-}
+source $testdir/fuzz_common.tcl
 
 #----------------------------------------------------------------
 # These tests caused errors that were first caught by the tests
diff --git a/test/fuzz_common.tcl b/test/fuzz_common.tcl
new file mode 100644 (file)
index 0000000..b552129
--- /dev/null
@@ -0,0 +1,392 @@
+# 2007 May 10
+#
+# 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.
+#
+#***********************************************************************
+#
+# $Id: fuzz_common.tcl,v 1.1 2007/05/30 10:36:47 danielk1977 Exp $
+
+proc fuzz {TemplateList} {
+  set n [llength $TemplateList]
+  set i [expr {int(rand()*$n)}]
+  set r [uplevel 1 subst -novar [list [lindex $TemplateList $i]]]
+
+  string map {"\n" " "} $r
+}
+
+# Fuzzy generation primitives:
+#
+#     Literal
+#     UnaryOp
+#     BinaryOp
+#     Expr
+#     Table
+#     Select
+#     Insert
+#
+
+# Returns a string representing an SQL literal.
+#
+proc Literal {} {
+  set TemplateList {
+    456 0 -456 1 -1 
+    2147483648 2147483647 2147483649 -2147483647 -2147483648 -2147483649
+    'The' 'first' 'experiments' 'in' 'hardware' 'fault' 'injection'
+    zeroblob(1000)
+    NULL
+    56.1 -56.1
+    123456789.1234567899
+  }
+  fuzz $TemplateList
+}
+
+# Returns a string containing an SQL unary operator (e.g. "+" or "NOT").
+#
+proc UnaryOp {} {
+  set TemplateList {+ - NOT ~}
+  fuzz $TemplateList
+}
+
+# Returns a string containing an SQL binary operator (e.g. "*" or "/").
+#
+proc BinaryOp {} {
+  set TemplateList {
+    || * / % + - << >> & | < <= > >= = == != <> AND OR
+    LIKE GLOB {NOT LIKE}
+  }
+  fuzz $TemplateList
+}
+
+# Return the complete text of an SQL expression.
+#
+set ::ExprDepth 0
+proc Expr { {c {}} } {
+  incr ::ExprDepth
+
+  set TemplateList [concat $c $c $c {[Literal]}]
+  if {$::ExprDepth < 3} {
+    lappend TemplateList \
+      {[Expr $c] [BinaryOp] [Expr $c]}                              \
+      {[UnaryOp] [Expr $c]}                                         \
+      {[Expr $c] ISNULL}                                            \
+      {[Expr $c] NOTNULL}                                           \
+      {CAST([Expr $c] AS blob)}                                     \
+      {CAST([Expr $c] AS text)}                                     \
+      {CAST([Expr $c] AS integer)}                                  \
+      {CAST([Expr $c] AS real)}                                     \
+      {abs([Expr])}                                                 \
+      {coalesce([Expr], [Expr])}                                    \
+      {hex([Expr])}                                                 \
+      {length([Expr])}                                              \
+      {lower([Expr])}                                               \
+      {upper([Expr])}                                               \
+      {quote([Expr])}                                               \
+      {random()}                                                    \
+      {randomblob(min(max([Expr],1), 500))}                         \
+      {typeof([Expr])}                                              \
+      {substr([Expr],[Expr],[Expr])}                                \
+      {CASE WHEN [Expr $c] THEN [Expr $c] ELSE [Expr $c] END}       \
+      {[Literal]} {[Literal]} {[Literal]}                           \
+      {[Literal]} {[Literal]} {[Literal]}                           \
+      {[Literal]} {[Literal]} {[Literal]}                           \
+      {[Literal]} {[Literal]} {[Literal]}
+  }
+  if {$::SelectDepth < 4} {
+    lappend TemplateList \
+      {([Select 1])}                       \
+      {[Expr $c] IN ([Select 1])}          \
+      {[Expr $c] NOT IN ([Select 1])}      \
+      {EXISTS ([Select 1])}                \
+  } 
+  set res [fuzz $TemplateList]
+  incr ::ExprDepth -1
+  return $res
+}
+
+# Return a valid table name.
+#
+set ::TableList [list]
+proc Table {} {
+  set TemplateList [concat sqlite_master $::TableList]
+  fuzz $TemplateList
+}
+
+# Return one of:
+#
+#     "SELECT DISTINCT", "SELECT ALL" or "SELECT"
+#
+proc SelectKw {} {
+  set TemplateList {
+    "SELECT DISTINCT"
+    "SELECT ALL"
+    "SELECT"
+  }
+  fuzz $TemplateList
+}
+
+# Return a result set for a SELECT statement.
+#
+proc ResultSet {{nRes 0} {c ""}} {
+  if {$nRes == 0} {
+    set nRes [expr {rand()*2 + 1}]
+  }
+
+  set aRes [list]
+  for {set ii 0} {$ii < $nRes} {incr ii} {
+    lappend aRes [Expr $c]
+  }
+
+  join $aRes ", "
+}
+
+set ::SelectDepth 0
+set ::ColumnList [list]
+proc SimpleSelect {{nRes 0}} {
+
+  set TemplateList {
+      {[SelectKw] [ResultSet $nRes]}
+  }
+
+  # The ::SelectDepth variable contains the number of ancestor SELECT
+  # statements (i.e. for a top level SELECT it is set to 0, for a
+  # sub-select 1, for a sub-select of a sub-select 2 etc.).
+  #
+  # If this is already greater than 3, do not generate a complicated
+  # SELECT statement. This tends to cause parser stack overflow (too
+  # boring to bother with).
+  #
+  if {$::SelectDepth < 4} {
+    lappend TemplateList \
+        {[SelectKw] [ResultSet $nRes $::ColumnList] FROM ([Select])}     \
+        {[SelectKw] [ResultSet $nRes] FROM ([Select])}                   \
+        {[SelectKw] [ResultSet $nRes $::ColumnList] FROM [Table]}        \
+        {
+             [SelectKw] [ResultSet $nRes $::ColumnList] 
+             FROM ([Select]) 
+             GROUP BY [Expr]
+             HAVING [Expr]
+        }                                                                \
+
+    if {0 == $nRes} {
+      lappend TemplateList                                               \
+          {[SelectKw] * FROM ([Select])}                                 \
+          {[SelectKw] * FROM [Table]}                                    \
+          {[SelectKw] * FROM [Table] WHERE [Expr $::ColumnList]}         \
+          {
+             [SelectKw] * 
+             FROM [Table],[Table] AS t2 
+             WHERE [Expr $::ColumnList] 
+          } {
+             [SelectKw] * 
+             FROM [Table] LEFT OUTER JOIN [Table] AS t2 
+             ON [Expr $::ColumnList]
+             WHERE [Expr $::ColumnList] 
+          }
+    }
+  } 
+
+  fuzz $TemplateList
+}
+
+# Return a SELECT statement.
+#
+# If boolean parameter $isExpr is set to true, make sure the
+# returned SELECT statement returns a single column of data.
+#
+proc Select {{nMulti 0}} {
+  set TemplateList {
+    {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} 
+    {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} 
+    {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} 
+    {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} 
+    {[SimpleSelect $nMulti] ORDER BY [Expr] DESC}
+    {[SimpleSelect $nMulti] ORDER BY [Expr] ASC}
+    {[SimpleSelect $nMulti] ORDER BY [Expr] ASC, [Expr] DESC}
+    {[SimpleSelect $nMulti] ORDER BY [Expr] LIMIT [Expr] OFFSET [Expr]}
+  }
+
+  if {$::SelectDepth < 4} {
+    if {$nMulti == 0} {
+      set nMulti [expr {(rand()*2)+1}]
+    }
+    lappend TemplateList                                             \
+        {[SimpleSelect $nMulti] UNION     [Select $nMulti]}          \
+        {[SimpleSelect $nMulti] UNION ALL [Select $nMulti]}          \
+        {[SimpleSelect $nMulti] EXCEPT    [Select $nMulti]}          \
+        {[SimpleSelect $nMulti] INTERSECT [Select $nMulti]}
+  }
+
+  incr ::SelectDepth
+  set res [fuzz $TemplateList]
+  incr ::SelectDepth -1
+  set res
+}
+
+# Generate and return a fuzzy INSERT statement.
+#
+proc Insert {} {
+  set TemplateList {
+      {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr]);}
+      {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr], [Expr]);}
+      {INSERT INTO [Table] VALUES([Expr], [Expr]);}
+  }
+  fuzz $TemplateList
+}
+
+proc Column {} {
+  fuzz $::ColumnList
+}
+
+# Generate and return a fuzzy UPDATE statement.
+#
+proc Update {} {
+  set TemplateList {
+    {UPDATE [Table] 
+     SET [Column] = [Expr $::ColumnList] 
+     WHERE [Expr $::ColumnList]}
+  }
+  fuzz $TemplateList
+}
+
+proc Delete {} {
+  set TemplateList {
+    {DELETE FROM [Table] WHERE [Expr $::ColumnList]}
+  }
+  fuzz $TemplateList
+}
+
+proc Statement {} {
+  set TemplateList {
+    {[Update]}
+    {[Insert]}
+    {[Select]}
+    {[Delete]}
+  }
+  fuzz $TemplateList
+}
+
+# Return an identifier. This just chooses randomly from a fixed set
+# of strings.
+proc Identifier {} {
+  set TemplateList {
+    This just chooses randomly a fixed 
+    We would also thank the developers 
+    for their analysis Samba
+  }
+  fuzz $TemplateList
+}
+
+proc Check {} {
+  # Use a large value for $::SelectDepth, because sub-selects are
+  # not allowed in expressions used by CHECK constraints.
+  #
+  set sd $::SelectDepth 
+  set ::SelectDepth 500
+  set TemplateList {
+    {}
+    {CHECK ([Expr])}
+  }
+  set res [fuzz $TemplateList]
+  set ::SelectDepth $sd
+  set res
+}
+
+proc Coltype {} {
+  set TemplateList {
+    {INTEGER PRIMARY KEY}
+    {VARCHAR [Check]}
+    {PRIMARY KEY}
+  }
+  fuzz $TemplateList
+}
+
+proc DropTable {} {
+  set TemplateList {
+    {DROP TABLE IF EXISTS [Identifier]}
+  }
+  fuzz $TemplateList
+}
+
+proc CreateView {} {
+  set TemplateList {
+    {CREATE VIEW [Identifier] AS [Select]}
+  }
+  fuzz $TemplateList
+}
+proc DropView {} {
+  set TemplateList {
+    {DROP VIEW IF EXISTS [Identifier]}
+  }
+  fuzz $TemplateList
+}
+
+proc CreateTable {} {
+  set TemplateList {
+    {CREATE TABLE [Identifier]([Identifier] [Coltype], [Identifier] [Coltype])}
+    {CREATE TEMP TABLE [Identifier]([Identifier] [Coltype])}
+  }
+  fuzz $TemplateList
+}
+
+proc CreateOrDropTableOrView {} {
+  set TemplateList {
+    {[CreateTable]}
+    {[DropTable]}
+    {[CreateView]}
+    {[DropView]}
+  }
+  fuzz $TemplateList
+}
+
+########################################################################
+
+set ::log [open fuzzy.log w]
+
+#
+# Usage: do_fuzzy_test <testname> ?<options>?
+# 
+#     -template
+#     -errorlist
+#     -repeats
+#     
+proc do_fuzzy_test {testname args} {
+  set ::fuzzyopts(-errorlist) [list]
+  set ::fuzzyopts(-repeats) $::REPEATS
+  array set ::fuzzyopts $args
+
+  lappend ::fuzzyopts(-errorlist) {parser stack overflow} 
+  lappend ::fuzzyopts(-errorlist) {ORDER BY}
+  lappend ::fuzzyopts(-errorlist) {GROUP BY}
+  lappend ::fuzzyopts(-errorlist) {datatype mismatch}
+
+  for {set ii 0} {$ii < $::fuzzyopts(-repeats)} {incr ii} {
+    do_test ${testname}.$ii {
+      set ::sql [subst $::fuzzyopts(-template)]
+      puts $::log $::sql
+      flush $::log
+      set rc [catch {execsql $::sql} msg]
+      set e 1
+      if {$rc} {
+        set e 0
+        foreach error $::fuzzyopts(-errorlist) {
+          if {0 == [string first $error $msg]} {
+            set e 1
+            break
+          }
+        }
+      }
+      if {$e == 0} {
+        puts ""
+        puts $::sql
+        puts $msg
+      }
+      set e
+    } {1}
+  }
+}
+
diff --git a/test/fuzz_malloc.test b/test/fuzz_malloc.test
new file mode 100644 (file)
index 0000000..71d723e
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# 2007 May 10
+#
+# 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 tests malloc failures in concert with fuzzy SQL generation.
+#
+# $Id: fuzz_malloc.test,v 1.1 2007/05/30 10:36:47 danielk1977 Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/fuzz_common.tcl
+source $testdir/malloc_common.tcl
+
+set ::REPEATS 20
+
+#
+# Usage: do_fuzzy_malloc_test <testname> ?<options>?
+# 
+#     -template
+#     -repeats
+#     
+proc do_fuzzy_malloc_test {testname args} {
+  set ::fuzzyopts(-repeats) $::REPEATS
+  array set ::fuzzyopts $args
+
+  for {set ii 0} {$ii < $::fuzzyopts(-repeats)} {incr ii} {
+    set ::sql [subst $::fuzzyopts(-template)]
+    # puts $::sql
+    foreach {rc res} [catchsql $::sql] {}
+    if {$rc==0} {
+      do_malloc_test $testname-$ii -sqlbody $::sql
+    } else {
+      incr ii -1
+    }
+  }
+}
+
+#----------------------------------------------------------------
+# Test malloc failure during parsing (and execution) of a fuzzily 
+# generated expressions.
+#
+do_fuzzy_malloc_test fuzzy_malloc-1 -template {Select [Expr]}
+
+sqlite_malloc_fail 0
+finish_test
index eac5548e2091a2200587ca8ab43a85a8ffc3a928..f9b280496ddc2c34e9e97a2be693c6824fd7d580 100644 (file)
@@ -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.41 2007/04/19 11:09:02 danielk1977 Exp $
+# $Id: malloc.test,v 1.42 2007/05/30 10:36:47 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -27,101 +27,7 @@ if {[info command sqlite_malloc_stat]==""} {
    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 malloc-$tn.$::n {
-
-      # Remove all traces of database files test.db and test2.db from the files
-      # system. Then open (empty database) "test.db" with the handle [db].
-      # 
-      sqlite_malloc_fail 0
-      catch {db close} 
-      catch {file delete -force test.db}
-      catch {file delete -force test.db-journal}
-      catch {file delete -force test2.db}
-      catch {file delete -force test2.db-journal}
-      catch {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
-}
+source $testdir/malloc_common.tcl
 
 do_malloc_test 1 -tclprep {
   db close
diff --git a/test/mallocB.test b/test/mallocB.test
new file mode 100644 (file)
index 0000000..9da2f6d
--- /dev/null
@@ -0,0 +1,35 @@
+# 2007 May 30
+#
+# 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).
+# These were all discovered by fuzzy generation of SQL. Apart from
+# that they have little in common.
+#
+# $Id: mallocB.test,v 1.1 2007/05/30 10:36:47 danielk1977 Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/malloc_common.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
+}
+
+do_malloc_test mallocB-1 -sqlbody {SELECT - 456}
+do_malloc_test mallocB-2 -sqlbody {SELECT - 456.1}
+do_malloc_test mallocB-3 -sqlbody {SELECT random()}
+do_malloc_test mallocB-4 -sqlbody {SELECT zeroblob(1000)}
+
+sqlite_malloc_fail 0
+finish_test
diff --git a/test/malloc_common.tcl b/test/malloc_common.tcl
new file mode 100644 (file)
index 0000000..1e84c53
--- /dev/null
@@ -0,0 +1,101 @@
+
+# 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
+
+  if {[string is integer $tn]} {
+    set tn malloc-$tn
+  }
+
+  set ::go 1
+  for {set ::n 1} {$::go && $::n < 50000} {incr ::n} {
+    do_test $tn.$::n {
+
+      # Remove all traces of database files test.db and test2.db from the files
+      # system. Then open (empty database) "test.db" with the handle [db].
+      # 
+      sqlite_malloc_fail 0
+      catch {db close} 
+      catch {file delete -force test.db}
+      catch {file delete -force test.db-journal}
+      catch {file delete -force test2.db}
+      catch {file delete -force test2.db-journal}
+      catch {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
+}
+
index f1d51ee40da7356fa77f47960ed65c26f499d6ab..6f033c37ea938ea7380d9db7cddd41e32b304ee7 100644 (file)
@@ -6,7 +6,7 @@
 #***********************************************************************
 # This file runs all tests.
 #
-# $Id: quick.test,v 1.57 2007/05/30 08:18:04 danielk1977 Exp $
+# $Id: quick.test,v 1.58 2007/05/30 10:36:47 danielk1977 Exp $
 
 proc lshift {lvar} {
   upvar $lvar l
@@ -46,6 +46,7 @@ set EXCLUDE {
   crash2.test
   exclusive3.test
   fuzz.test
+  fuzz_malloc.test
   in2.test
   loadext.test
   malloc.test
index 89a8f8c1c377287bda6d70cc0b7a5e729237932d..089264fc3141075134403930b0050b70ccc85208 100644 (file)
@@ -11,7 +11,7 @@
 # This file is the driver for the "soak" tests. It is a peer of the
 # quick.test and all.test scripts.
 #
-# $Id: soak.test,v 1.1 2007/05/30 08:18:04 danielk1977 Exp $
+# $Id: soak.test,v 1.2 2007/05/30 10:36:47 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -60,6 +60,7 @@ set argv [list]
 #
 set SOAKTESTS {
   fuzz.test
+  fuzz_malloc.test
   trans.test
 }