Add some extra tests for malloc failure during expression parsing and execution using fuzzily generated SQL. (CVS 4043)
FossilOrigin-Name: 7522d2fb3204d107b8b4816d7f39c88741f20230
This commit is contained in:
parent
5453b8da9e
commit
c9cf901d8c
28
manifest
28
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
|
||||
|
@ -1 +1 @@
|
||||
5d0b247ca1667f5d773bda337cb6f58c3b14676a
|
||||
7522d2fb3204d107b8b4816d7f39c88741f20230
|
19
src/expr.c
19
src/expr.c
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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){
|
||||
|
381
test/fuzz.test
381
test/fuzz.test
@ -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
|
||||
|
392
test/fuzz_common.tcl
Normal file
392
test/fuzz_common.tcl
Normal file
@ -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}
|
||||
}
|
||||
}
|
||||
|
53
test/fuzz_malloc.test
Normal file
53
test/fuzz_malloc.test
Normal file
@ -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
|
@ -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
|
||||
|
35
test/mallocB.test
Normal file
35
test/mallocB.test
Normal file
@ -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
|
101
test/malloc_common.tcl
Normal file
101
test/malloc_common.tcl
Normal file
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user