Index: src/loadext.c ================================================================== --- src/loadext.c +++ src/loadext.c @@ -466,10 +466,12 @@ #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_drop_modules, #else 0, #endif + /* Version 3.31.0 and later */ + sqlite3_hard_heap_limit64, }; /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a Index: src/malloc.c ================================================================== --- src/malloc.c +++ src/malloc.c @@ -30,23 +30,31 @@ UNUSED_PARAMETER(n); return 0; #endif } +/* +** Default value of the hard heap limit. 0 means "no limit". +*/ +#ifndef SQLITE_MAX_MEMORY +# define SQLITE_MAX_MEMORY 0 +#endif + /* ** State information local to the memory allocation subsystem. */ static SQLITE_WSD struct Mem0Global { sqlite3_mutex *mutex; /* Mutex to serialize access */ sqlite3_int64 alarmThreshold; /* The soft heap limit */ + sqlite3_int64 hardLimit; /* The hard upper bound on memory */ /* ** True if heap is nearly "full" where "full" is defined by the ** sqlite3_soft_heap_limit() setting. */ int nearlyFull; -} mem0 = { 0, 0, 0 }; +} mem0 = { 0, SQLITE_MAX_MEMORY, SQLITE_MAX_MEMORY, 0 }; #define mem0 GLOBAL(struct Mem0Global, mem0) /* ** Return the memory allocator mutex. sqlite3_status() needs it. @@ -72,12 +80,19 @@ return SQLITE_OK; } #endif /* -** Set the soft heap-size limit for the library. Passing a zero or -** negative value indicates no limit. +** Set the soft heap-size limit for the library. An argument of +** zero disables the limit. A negative argument is a no-op used to +** obtain the return value. +** +** The return value is the value of the heap limit just before this +** interface was called. +** +** If the hard heap limit is enabled, then the soft heap limit cannot +** be disabled nor raised above the hard heap limit. */ sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){ sqlite3_int64 priorLimit; sqlite3_int64 excess; sqlite3_int64 nUsed; @@ -88,10 +103,13 @@ sqlite3_mutex_enter(mem0.mutex); priorLimit = mem0.alarmThreshold; if( n<0 ){ sqlite3_mutex_leave(mem0.mutex); return priorLimit; + } + if( mem0.hardLimit>0 && (n>mem0.hardLimit || n==0) ){ + n = mem0.hardLimit; } mem0.alarmThreshold = n; nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); mem0.nearlyFull = (n>0 && n<=nUsed); sqlite3_mutex_leave(mem0.mutex); @@ -101,10 +119,41 @@ } void sqlite3_soft_heap_limit(int n){ if( n<0 ) n = 0; sqlite3_soft_heap_limit64(n); } + +/* +** Set the hard heap-size limit for the library. An argument of zero +** disables the hard heap limit. A negative argument is a no-op used +** to obtain the return value without affecting the hard heap limit. +** +** The return value is the value of the hard heap limit just prior to +** calling this interface. +** +** Setting the hard heap limit will also activate the soft heap limit +** and constrain the soft heap limit to be no more than the hard heap +** limit. +*/ +sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 n){ + sqlite3_int64 priorLimit; +#ifndef SQLITE_OMIT_AUTOINIT + int rc = sqlite3_initialize(); + if( rc ) return -1; +#endif + sqlite3_mutex_enter(mem0.mutex); + priorLimit = mem0.hardLimit; + if( n>=0 ){ + mem0.hardLimit = n; + if( nSQLITE_MAX_MEMORY ){ - *pp = 0; - return; - } -#endif - sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n); if( mem0.alarmThreshold>0 ){ sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed >= mem0.alarmThreshold - nFull ){ mem0.nearlyFull = 1; sqlite3MallocAlarm(nFull); + if( mem0.hardLimit ){ + nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); + if( nUsed >= mem0.hardLimit - nFull ){ + *pp = 0; + return; + } + } }else{ mem0.nearlyFull = 0; } } p = sqlite3GlobalConfig.m.xMalloc(nFull); Index: src/pragma.c ================================================================== --- src/pragma.c +++ src/pragma.c @@ -2086,10 +2086,31 @@ sqlite3_soft_heap_limit64(N); } returnSingleInt(v, sqlite3_soft_heap_limit64(-1)); break; } + + /* + ** PRAGMA hard_heap_limit + ** PRAGMA hard_heap_limit = N + ** + ** Invoke sqlite3_hard_heap_limit64() to query or set the hard heap + ** limit. The hard heap limit can be activated or lowered by this + ** pragma, but not raised or deactivated. Only the + ** sqlite3_hard_heap_limit64() C-language API can raise or deactivate + ** the hard heap limit. This allows an application to set a heap limit + ** constraint that cannot be relaxed by an untrusted SQL script. + */ + case PragTyp_HARD_HEAP_LIMIT: { + sqlite3_int64 N; + if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ + sqlite3_int64 iPrior = sqlite3_hard_heap_limit64(-1); + if( N>0 && (iPrior==0 || iPrior>N) ) sqlite3_hard_heap_limit64(N); + } + returnSingleInt(v, sqlite3_hard_heap_limit64(-1)); + break; + } /* ** PRAGMA threads ** PRAGMA threads = N ** Index: src/pragma.h ================================================================== --- src/pragma.h +++ src/pragma.h @@ -19,38 +19,39 @@ #define PragTyp_DEFAULT_CACHE_SIZE 11 #define PragTyp_ENCODING 12 #define PragTyp_FOREIGN_KEY_CHECK 13 #define PragTyp_FOREIGN_KEY_LIST 14 #define PragTyp_FUNCTION_LIST 15 -#define PragTyp_INCREMENTAL_VACUUM 16 -#define PragTyp_INDEX_INFO 17 -#define PragTyp_INDEX_LIST 18 -#define PragTyp_INTEGRITY_CHECK 19 -#define PragTyp_JOURNAL_MODE 20 -#define PragTyp_JOURNAL_SIZE_LIMIT 21 -#define PragTyp_LOCK_PROXY_FILE 22 -#define PragTyp_LOCKING_MODE 23 -#define PragTyp_PAGE_COUNT 24 -#define PragTyp_MMAP_SIZE 25 -#define PragTyp_MODULE_LIST 26 -#define PragTyp_OPTIMIZE 27 -#define PragTyp_PAGE_SIZE 28 -#define PragTyp_PRAGMA_LIST 29 -#define PragTyp_SECURE_DELETE 30 -#define PragTyp_SHRINK_MEMORY 31 -#define PragTyp_SOFT_HEAP_LIMIT 32 -#define PragTyp_SYNCHRONOUS 33 -#define PragTyp_TABLE_INFO 34 -#define PragTyp_TEMP_STORE 35 -#define PragTyp_TEMP_STORE_DIRECTORY 36 -#define PragTyp_THREADS 37 -#define PragTyp_WAL_AUTOCHECKPOINT 38 -#define PragTyp_WAL_CHECKPOINT 39 -#define PragTyp_ACTIVATE_EXTENSIONS 40 -#define PragTyp_KEY 41 -#define PragTyp_LOCK_STATUS 42 -#define PragTyp_STATS 43 +#define PragTyp_HARD_HEAP_LIMIT 16 +#define PragTyp_INCREMENTAL_VACUUM 17 +#define PragTyp_INDEX_INFO 18 +#define PragTyp_INDEX_LIST 19 +#define PragTyp_INTEGRITY_CHECK 20 +#define PragTyp_JOURNAL_MODE 21 +#define PragTyp_JOURNAL_SIZE_LIMIT 22 +#define PragTyp_LOCK_PROXY_FILE 23 +#define PragTyp_LOCKING_MODE 24 +#define PragTyp_PAGE_COUNT 25 +#define PragTyp_MMAP_SIZE 26 +#define PragTyp_MODULE_LIST 27 +#define PragTyp_OPTIMIZE 28 +#define PragTyp_PAGE_SIZE 29 +#define PragTyp_PRAGMA_LIST 30 +#define PragTyp_SECURE_DELETE 31 +#define PragTyp_SHRINK_MEMORY 32 +#define PragTyp_SOFT_HEAP_LIMIT 33 +#define PragTyp_SYNCHRONOUS 34 +#define PragTyp_TABLE_INFO 35 +#define PragTyp_TEMP_STORE 36 +#define PragTyp_TEMP_STORE_DIRECTORY 37 +#define PragTyp_THREADS 38 +#define PragTyp_WAL_AUTOCHECKPOINT 39 +#define PragTyp_WAL_CHECKPOINT 40 +#define PragTyp_ACTIVATE_EXTENSIONS 41 +#define PragTyp_KEY 42 +#define PragTyp_LOCK_STATUS 43 +#define PragTyp_STATS 44 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ #define PragFlg_NoColumns 0x02 /* OP_ResultRow called with zero columns */ #define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */ @@ -317,10 +318,15 @@ /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 41, 2, /* iArg: */ 0 }, #endif #endif + {/* zName: */ "hard_heap_limit", + /* ePragTyp: */ PragTyp_HARD_HEAP_LIMIT, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #if defined(SQLITE_HAS_CODEC) {/* zName: */ "hexkey", /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, @@ -661,6 +667,6 @@ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, #endif }; -/* Number of pragmas: 64 on by default, 80 total. */ +/* Number of pragmas: 65 on by default, 81 total. */ Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -1740,10 +1740,11 @@ **
^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, ** interpreted as a boolean, which enables or disables the collection of ** memory allocation statistics. ^(When memory allocation statistics are ** disabled, the following SQLite interfaces become non-operational: ** )^ @@ -6136,10 +6137,13 @@ */ int sqlite3_db_release_memory(sqlite3*); /* ** CAPI3REF: Impose A Limit On Heap Size +** +** These interfaces impose limits on the amount of heap memory that will be +** by all database connections within a single process. ** ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the ** soft limit on the amount of heap memory that may be allocated by SQLite. ** ^SQLite strives to keep heap memory utilization below the soft heap ** limit by reducing the number of pages held in the page cache @@ -6147,24 +6151,45 @@ ** ^The soft heap limit is "soft" because even though SQLite strives to stay ** below the limit, it will exceed the limit rather than generate ** an [SQLITE_NOMEM] error. In other words, the soft heap limit ** is advisory only. ** -** ^The return value from sqlite3_soft_heap_limit64() is the size of -** the soft heap limit prior to the call, or negative in the case of an +** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of +** N bytes on the amount of memory that will be allocated. ^The +** sqlite3_hard_heap_limit64(N) interface is similar to +** sqlite3_soft_heap_limit64(N) except that memory allocations will fail +** when the hard heap limit is reached. +** +** ^The return value from both sqlite3_soft_heap_limit64() and +** sqlite3_hard_heap_limit64() is the size of +** the heap limit prior to the call, or negative in the case of an ** error. ^If the argument N is negative -** then no change is made to the soft heap limit. Hence, the current -** size of the soft heap limit can be determined by invoking -** sqlite3_soft_heap_limit64() with a negative argument. +** then no change is made to the heap limit. Hence, the current +** size of heap limits can be determined by invoking +** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). ** -** ^If the argument N is zero then the soft heap limit is disabled. +** ^Setting the heap limits to zero disables the heap limiter mechanism. ** -** ^(The soft heap limit is not enforced in the current implementation +** ^The soft heap limit may not be greater than the hard heap limit. +** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) +** is invoked with a value of N that is greater than the hard heap limit, +** the the soft heap limit is set to the value of the hard heap limit. +** ^The soft heap limit is automatically enabled whenever the hard heap +** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and +** the soft heap limit is outside the range of 1..N, then the soft heap +** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the +** hard heap limit is enabled makes the soft heap limit equal to the +** hard heap limit. +** +** The memory allocation limits can also be adjusted using +** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit]. +** +** ^(The heap limits are not enforced in the current implementation ** if one or more of following conditions are true: ** ** )^ ** -** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), -** the soft heap limit is enforced -** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] -** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT], -** the soft heap limit is enforced on every memory allocation. Without -** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced -** when memory is allocated by the page cache. Testing suggests that because -** the page cache is the predominate memory user in SQLite, most -** applications will achieve adequate soft heap limit enforcement without -** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT]. -** -** The circumstances under which SQLite will enforce the soft heap limit may +** The circumstances under which SQLite will enforce the heap limits may ** changes in future releases of SQLite. */ sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); +sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N); /* ** CAPI3REF: Deprecated Soft Heap Limit Interface ** DEPRECATED ** Index: src/sqlite3ext.h ================================================================== --- src/sqlite3ext.h +++ src/sqlite3ext.h @@ -322,10 +322,11 @@ /* Version 3.28.0 and later */ int (*stmt_isexplain)(sqlite3_stmt*); int (*value_frombind)(sqlite3_value*); /* Version 3.30.0 and later */ int (*drop_modules)(sqlite3*,const char**); + sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64); }; /* ** This is the function signature used for all extension entry points. It ** is also defined in the file "loadext.c". @@ -616,10 +617,11 @@ /* Version 3.28.0 and later */ #define sqlite3_stmt_isexplain sqlite3_api->isexplain #define sqlite3_value_frombind sqlite3_api->frombind /* Version 3.30.0 and later */ #define sqlite3_drop_modules sqlite3_api->drop_modules +#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) /* This case when the file really is being compiled as a loadable ** extension */ Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -5523,10 +5523,37 @@ } amt = sqlite3_soft_heap_limit64(N); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt)); return TCL_OK; } + +/* +** Usage: sqlite3_hard_heap_limit ?N? +** +** Query or set the hard heap limit for the current thread. The +** limit is only changed if the N is present. The previous limit +** is returned. +*/ +static int SQLITE_TCLAPI test_hard_heap_limit( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_int64 amt; + Tcl_WideInt N = -1; + if( objc!=1 && objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "?N?"); + return TCL_ERROR; + } + if( objc==2 ){ + if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR; + } + amt = sqlite3_hard_heap_limit64(N); + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt)); + return TCL_OK; +} /* ** Usage: sqlite3_thread_cleanup ** ** Call the sqlite3_thread_cleanup API. @@ -7976,10 +8003,12 @@ { "sqlite3_db_cacheflush", test_db_cacheflush, 0}, { "sqlite3_system_errno", test_system_errno, 0}, { "sqlite3_db_filename", test_db_filename, 0}, { "sqlite3_db_readonly", test_db_readonly, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, + { "sqlite3_soft_heap_limit64", test_soft_heap_limit, 0}, + { "sqlite3_hard_heap_limit64", test_hard_heap_limit, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, { "sqlite3_load_extension", test_load_extension, 0}, { "sqlite3_enable_load_extension", test_enable_load, 0}, Index: src/treeview.c ================================================================== --- src/treeview.c +++ src/treeview.c @@ -64,11 +64,11 @@ } if( zFormat!=0 ){ va_start(ap, zFormat); sqlite3_str_vappendf(&acc, zFormat, ap); va_end(ap); - assert( acc.nChar>0 ); + assert( acc.nChar>0 || acc.accError ); sqlite3_str_append(&acc, "\n", 1); } sqlite3StrAccumFinish(&acc); fprintf(stdout,"%s", zBuf); fflush(stdout); Index: test/fuzzcheck.c ================================================================== --- test/fuzzcheck.c +++ test/fuzzcheck.c @@ -450,10 +450,13 @@ /* Maximum number of progress handler callbacks */ static unsigned int mxProgressCb = 2000; /* Maximum string length in SQLite */ static int lengthLimit = 1000000; + +/* Limit on the amount of heap memory that can be used */ +static sqlite3_int64 heapLimit = 1000000000; /* Maximum byte-code program length in SQLite */ static int vdbeOpLimit = 25000; /* Maximum size of the in-memory database */ @@ -775,10 +778,11 @@ sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, vdbeOpLimit); } if( lengthLimit>0 ){ sqlite3_limit(cx.db, SQLITE_LIMIT_LENGTH, lengthLimit); } + sqlite3_hard_heap_limit64(heapLimit); if( nDb>=20 && aDb[18]==2 && aDb[19]==2 ){ aDb[18] = aDb[19] = 1; } rc = sqlite3_deserialize(cx.db, "main", aDb, nDb, nDb, @@ -1339,11 +1343,11 @@ char *zDbName = ""; /* Appreviated name of a source database */ const char *zFailCode = 0; /* Value of the TEST_FAILURE env variable */ int cellSzCkFlag = 0; /* --cell-size-check */ int sqlFuzz = 0; /* True for SQL fuzz. False for DB fuzz */ int iTimeout = 120; /* Default 120-second timeout */ - int nMem = 0; /* Memory limit */ + int nMem = 0; /* Memory limit override */ int nMemThisDb = 0; /* Memory limit set by the CONFIG table */ char *zExpDb = 0; /* Write Databases to files in this directory */ char *zExpSql = 0; /* Write SQL to files in this directory */ void *pHeap = 0; /* Heap for use by SQLite */ int ossFuzz = 0; /* enable OSS-FUZZ testing */ @@ -1389,17 +1393,12 @@ }else if( strcmp(z,"info")==0 ){ infoFlag = 1; }else if( strcmp(z,"limit-mem")==0 ){ -#if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5) - fatalError("the %s option requires -DSQLITE_ENABLE_MEMSYS5 or _MEMSYS3", - argv[i]); -#else if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); nMem = integerValue(argv[++i]); -#endif }else if( strcmp(z,"limit-vdbe")==0 ){ vdbeLimitFlag = 1; }else if( strcmp(z,"load-sql")==0 ){ @@ -1584,18 +1583,13 @@ if( zName==0 ) continue; if( strcmp(zName, "oss-fuzz")==0 ){ ossFuzzThisDb = sqlite3_column_int(pStmt,1); if( verboseFlag ) printf("Config: oss-fuzz=%d\n", ossFuzzThisDb); } - if( strcmp(zName, "limit-mem")==0 && !nativeMalloc ){ -#if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5) - fatalError("the limit-mem option requires -DSQLITE_ENABLE_MEMSYS5" - " or _MEMSYS3"); -#else + if( strcmp(zName, "limit-mem")==0 ){ nMemThisDb = sqlite3_column_int(pStmt,1); if( verboseFlag ) printf("Config: limit-mem=%d\n", nMemThisDb); -#endif } } sqlite3_finalize(pStmt); } @@ -1718,16 +1712,22 @@ fatalError("SQLite has memory in use before the start of testing"); } /* Limit available memory, if requested */ sqlite3_shutdown(); - if( nMemThisDb>0 && !nativeMalloc ){ - pHeap = realloc(pHeap, nMemThisDb); - if( pHeap==0 ){ - fatalError("failed to allocate %d bytes of heap memory", nMem); + if( nMemThisDb>0 && nMem==0 ){ + if( !nativeMalloc ){ + pHeap = realloc(pHeap, nMemThisDb); + if( pHeap==0 ){ + fatalError("failed to allocate %d bytes of heap memory", nMem); + } + sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nMemThisDb, 128); + }else{ + sqlite3_hard_heap_limit64((sqlite3_int64)nMemThisDb); } - sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nMemThisDb, 128); + }else{ + sqlite3_hard_heap_limit64(0); } /* Disable lookaside with the --native-malloc option */ if( nativeMalloc ){ sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0); Index: test/ossfuzz.c ================================================================== --- test/ossfuzz.c +++ test/ossfuzz.c @@ -152,10 +152,13 @@ sqlite3_progress_handler(cx.db, 10, progress_handler, (void*)&cx); #endif /* Set a limit on the maximum size of a prepared statement */ sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, 25000); + + /* Limit total memory available to SQLite to 20MB */ + sqlite3_hard_heap_limit64(20000000); /* Set a limit on the maximum length of a string or BLOB. Without this ** limit, fuzzers will invoke randomblob(N) for a large N, and the process ** will timeout trying to generate the huge blob */ sqlite3_limit(cx.db, SQLITE_LIMIT_LENGTH, 50000); Index: test/tester.tcl ================================================================== --- test/tester.tcl +++ test/tester.tcl @@ -386,10 +386,11 @@ # proc print_help_and_quit {} { puts {Options: --pause Wait for user input before continuing --soft-heap-limit=N Set the soft-heap-limit to N + --hard-heap-limit=N Set the hard-heap-limit to N --maxerror=N Quit after N errors --verbose=(0|1) Control the amount of output. Default '1' --output=FILE set --verbose=2 and output to FILE. Implies -q -q Shorthand for --verbose=0 --help This message @@ -406,10 +407,11 @@ # Parse any options specified in the $argv array. This script accepts the # following options: # # --pause # --soft-heap-limit=NN + # --hard-heap-limit=NN # --maxerror=NN # --malloctrace=N # --backtrace=N # --binarylog=N # --soak=N @@ -422,10 +424,11 @@ # -q Reduce output # --testdir=$dir Run tests in subdirectory $dir # --help # set cmdlinearg(soft-heap-limit) 0 + set cmdlinearg(hard-heap-limit) 0 set cmdlinearg(maxerror) 1000 set cmdlinearg(malloctrace) 0 set cmdlinearg(backtrace) 10 set cmdlinearg(binarylog) 0 set cmdlinearg(soak) 0 @@ -448,10 +451,13 @@ gets stdin } {^-+soft-heap-limit=.+$} { foreach {dummy cmdlinearg(soft-heap-limit)} [split $a =] break } + {^-+hard-heap-limit=.+$} { + foreach {dummy cmdlinearg(hard-heap-limit)} [split $a =] break + } {^-+maxerror=.+$} { foreach {dummy cmdlinearg(maxerror)} [split $a =] break } {^-+malloctrace=.+$} { foreach {dummy cmdlinearg(malloctrace)} [split $a =] break @@ -584,11 +590,12 @@ # Update the soft-heap-limit each time this script is run. In that # way if an individual test file changes the soft-heap-limit, it # will be reset at the start of the next test file. # -sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit) +sqlite3_soft_heap_limit64 $cmdlinearg(soft-heap-limit) +sqlite3_hard_heap_limit64 $cmdlinearg(hard-heap-limit) # Create a test database # proc reset_db {} { catch {db close} @@ -1205,11 +1212,12 @@ sqlite3 db {} # sqlite3_clear_tsd_memdebug db close sqlite3_reset_auto_extension - sqlite3_soft_heap_limit 0 + sqlite3_soft_heap_limit64 0 + sqlite3_hard_heap_limit64 0 set nTest [incr_ntest] set nErr [set_test_counter errors] set nKnown 0 if {[file readable known-problems.txt]} { Index: tool/mkpragmatab.tcl ================================================================== --- tool/mkpragmatab.tcl +++ tool/mkpragmatab.tcl @@ -398,10 +398,13 @@ NAME: activate_extensions IF: defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) NAME: soft_heap_limit FLAG: Result0 + + NAME: hard_heap_limit + FLAG: Result0 NAME: threads FLAG: Result0 NAME: optimize