| OLD | NEW | 
 | (Empty) | 
|    1 # 2007 May 05 |  | 
|    2 # |  | 
|    3 # The author disclaims copyright to this source code.  In place of |  | 
|    4 # a legal notice, here is a blessing: |  | 
|    5 # |  | 
|    6 #    May you do good and not evil. |  | 
|    7 #    May you find forgiveness for yourself and forgive others. |  | 
|    8 #    May you share freely, never taking more than you give. |  | 
|    9 # |  | 
|   10 #*********************************************************************** |  | 
|   11 # |  | 
|   12 # This file contains common code used by many different malloc tests |  | 
|   13 # within the test suite. |  | 
|   14 # |  | 
|   15 # $Id: malloc_common.tcl,v 1.22 2008/09/23 16:41:30 danielk1977 Exp $ |  | 
|   16  |  | 
|   17 # If we did not compile with malloc testing enabled, then do nothing. |  | 
|   18 # |  | 
|   19 ifcapable builtin_test { |  | 
|   20   set MEMDEBUG 1 |  | 
|   21 } else { |  | 
|   22   set MEMDEBUG 0 |  | 
|   23   return 0 |  | 
|   24 } |  | 
|   25  |  | 
|   26 # Usage: do_malloc_test <test number> <options...> |  | 
|   27 # |  | 
|   28 # The first argument, <test number>, is an integer used to name the |  | 
|   29 # tests executed by this proc. Options are as follows: |  | 
|   30 # |  | 
|   31 #     -tclprep          TCL script to run to prepare test. |  | 
|   32 #     -sqlprep          SQL script to run to prepare test. |  | 
|   33 #     -tclbody          TCL script to run with malloc failure simulation. |  | 
|   34 #     -sqlbody          TCL script to run with malloc failure simulation. |  | 
|   35 #     -cleanup          TCL script to run after the test. |  | 
|   36 # |  | 
|   37 # This command runs a series of tests to verify SQLite's ability |  | 
|   38 # to handle an out-of-memory condition gracefully. It is assumed |  | 
|   39 # that if this condition occurs a malloc() call will return a |  | 
|   40 # NULL pointer. Linux, for example, doesn't do that by default. See |  | 
|   41 # the "BUGS" section of malloc(3). |  | 
|   42 # |  | 
|   43 # Each iteration of a loop, the TCL commands in any argument passed |  | 
|   44 # to the -tclbody switch, followed by the SQL commands in any argument |  | 
|   45 # passed to the -sqlbody switch are executed. Each iteration the |  | 
|   46 # Nth call to sqliteMalloc() is made to fail, where N is increased |  | 
|   47 # each time the loop runs starting from 1. When all commands execute |  | 
|   48 # successfully, the loop ends. |  | 
|   49 # |  | 
|   50 proc do_malloc_test {tn args} { |  | 
|   51   array unset ::mallocopts  |  | 
|   52   array set ::mallocopts $args |  | 
|   53  |  | 
|   54   if {[string is integer $tn]} { |  | 
|   55     set tn malloc-$tn |  | 
|   56   } |  | 
|   57   if {[info exists ::mallocopts(-start)]} { |  | 
|   58     set start $::mallocopts(-start) |  | 
|   59   } else { |  | 
|   60     set start 0 |  | 
|   61   } |  | 
|   62   if {[info exists ::mallocopts(-end)]} { |  | 
|   63     set end $::mallocopts(-end) |  | 
|   64   } else { |  | 
|   65     set end 50000 |  | 
|   66   } |  | 
|   67   save_prng_state |  | 
|   68  |  | 
|   69   foreach ::iRepeat {0 10000000} { |  | 
|   70     set ::go 1 |  | 
|   71     for {set ::n $start} {$::go && $::n <= $end} {incr ::n} { |  | 
|   72  |  | 
|   73       # If $::iRepeat is 0, then the malloc() failure is transient - it |  | 
|   74       # fails and then subsequent calls succeed. If $::iRepeat is 1,  |  | 
|   75       # then the failure is persistent - once malloc() fails it keeps |  | 
|   76       # failing. |  | 
|   77       # |  | 
|   78       set zRepeat "transient" |  | 
|   79       if {$::iRepeat} {set zRepeat "persistent"} |  | 
|   80       restore_prng_state |  | 
|   81       foreach file [glob -nocomplain test.db-mj*] {file delete -force $file} |  | 
|   82  |  | 
|   83       do_test ${tn}.${zRepeat}.${::n} { |  | 
|   84    |  | 
|   85         # Remove all traces of database files test.db and test2.db  |  | 
|   86         # from the file-system. Then open (empty database) "test.db"  |  | 
|   87         # with the handle [db]. |  | 
|   88         #  |  | 
|   89         catch {db close}  |  | 
|   90         catch {file delete -force test.db} |  | 
|   91         catch {file delete -force test.db-journal} |  | 
|   92         catch {file delete -force test2.db} |  | 
|   93         catch {file delete -force test2.db-journal} |  | 
|   94         if {[info exists ::mallocopts(-testdb)]} { |  | 
|   95           file copy $::mallocopts(-testdb) test.db |  | 
|   96         } |  | 
|   97         catch { sqlite3 db test.db } |  | 
|   98         if {[info commands db] ne ""} { |  | 
|   99           sqlite3_extended_result_codes db 1 |  | 
|  100         } |  | 
|  101         sqlite3_db_config_lookaside db 0 0 0 |  | 
|  102    |  | 
|  103         # Execute any -tclprep and -sqlprep scripts. |  | 
|  104         # |  | 
|  105         if {[info exists ::mallocopts(-tclprep)]} { |  | 
|  106           eval $::mallocopts(-tclprep) |  | 
|  107         } |  | 
|  108         if {[info exists ::mallocopts(-sqlprep)]} { |  | 
|  109           execsql $::mallocopts(-sqlprep) |  | 
|  110         } |  | 
|  111    |  | 
|  112         # Now set the ${::n}th malloc() to fail and execute the -tclbody  |  | 
|  113         # and -sqlbody scripts. |  | 
|  114         # |  | 
|  115         sqlite3_memdebug_fail $::n -repeat $::iRepeat |  | 
|  116         set ::mallocbody {} |  | 
|  117         if {[info exists ::mallocopts(-tclbody)]} { |  | 
|  118           append ::mallocbody "$::mallocopts(-tclbody)\n" |  | 
|  119         } |  | 
|  120         if {[info exists ::mallocopts(-sqlbody)]} { |  | 
|  121           append ::mallocbody "db eval {$::mallocopts(-sqlbody)}" |  | 
|  122         } |  | 
|  123  |  | 
|  124         # The following block sets local variables as follows: |  | 
|  125         # |  | 
|  126         #     isFail  - True if an error (any error) was reported by sqlite. |  | 
|  127         #     nFail   - The total number of simulated malloc() failures. |  | 
|  128         #     nBenign - The number of benign simulated malloc() failures. |  | 
|  129         # |  | 
|  130         set isFail [catch $::mallocbody msg] |  | 
|  131         set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign] |  | 
|  132         # puts -nonewline " (isFail=$isFail nFail=$nFail nBenign=$nBenign) " |  | 
|  133  |  | 
|  134         # If one or more mallocs failed, run this loop body again. |  | 
|  135         # |  | 
|  136         set go [expr {$nFail>0}] |  | 
|  137  |  | 
|  138         if {($nFail-$nBenign)==0} { |  | 
|  139           if {$isFail} { |  | 
|  140             set v2 $msg |  | 
|  141           } else { |  | 
|  142             set isFail 1 |  | 
|  143             set v2 1 |  | 
|  144           } |  | 
|  145         } elseif {!$isFail} { |  | 
|  146           set v2 $msg |  | 
|  147         } elseif { |  | 
|  148           [info command db]=="" ||  |  | 
|  149           [db errorcode]==7 || |  | 
|  150           $msg=="out of memory" |  | 
|  151         } { |  | 
|  152           set v2 1 |  | 
|  153         } else { |  | 
|  154           set v2 $msg |  | 
|  155           puts [db errorcode] |  | 
|  156         } |  | 
|  157         lappend isFail $v2 |  | 
|  158       } {1 1} |  | 
|  159    |  | 
|  160       if {[info exists ::mallocopts(-cleanup)]} { |  | 
|  161         catch [list uplevel #0 $::mallocopts(-cleanup)] msg |  | 
|  162       } |  | 
|  163     } |  | 
|  164   } |  | 
|  165   unset ::mallocopts |  | 
|  166   sqlite3_memdebug_fail -1 |  | 
|  167 } |  | 
| OLD | NEW |