From: larrybr Date: Tue, 16 May 2023 14:45:19 +0000 (+0000) Subject: Use CLI resmanage to ensure input redirection is unwound on abort. Remove unused... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=555fe8a08e42c1880d4b01919b54eb9012d4cb57;p=thirdparty%2Fsqlite.git Use CLI resmanage to ensure input redirection is unwound on abort. Remove unused resmanage feature. Extend no-leak-on-abort fraction. Fix unlikely (and old) GPF upon OOM. FossilOrigin-Name: 243085279c6f8c51ad85bdc1e7c07ef6f858067640a7330f77d0bf94ed11b438 --- diff --git a/manifest b/manifest index f70d040be5..f9811b8f69 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C CLI\sdebug\sbuild\sready\sfor\stesting\swhether\sOOM\shandling\sis\swell-behaved. -D 2023-05-15T23:43:26.974 +C Use\sCLI\sresmanage\sto\sensure\sinput\sredirection\sis\sunwound\son\sabort.\sRemove\sunused\sresmanage\sfeature.\sExtend\sno-leak-on-abort\sfraction.\sFix\sunlikely\s(and\sold)\sGPF\supon\sOOM. +D 2023-05-16T14:45:19.983 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -638,12 +638,12 @@ F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/prepare.c 6350675966bd0e7ac3a464af9dbfe26db6f0d4237f4e1f1acdb17b12ad371e6e F src/printf.c b9320cdbeca0b336c3f139fd36dd121e4167dd62b35fbe9ccaa9bab44c0af38d F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c -F src/resmanage.c 0d0525e595998ef59b9e4bcc0a29674730be921e63b1d6decdd90e294258feca -F src/resmanage.h 7caffb310388a25d147018752a25a5b1a85a2c21478ec723eddc5def64a9148a +F src/resmanage.c 6b1e468adaa4343537e5b3b6746325b111961d7ff6122735a73f49e208d01df0 +F src/resmanage.h e4fd319ae38bc1c363190b3fb374788c40b5986f92183db779269cb8b9340c15 F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 738c3a3d6929f8be66c319bad17f6b297bd60a4eb14006075c48a28487dc7786 -F src/shell.c.in 5ef3ad16114a5bbb4e4c765f6ab718e48fc53e4f819a5ed86626dc79145543e8 +F src/shell.c.in 071bd4ae867d42a372e517fd101b77cb10372a914eee5dd0c9dec4f4c753fe85 F src/shext_linkage.h 27dcf7624df05b2a7a6d367834339a6db3636f3035157f641f7db2ec499f8f6d F src/sqlite.h.in c14a4471fcd897a03631ac7ad3d05505e895e7b6419ec5b96cae9bc4df7a9fc6 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -2081,8 +2081,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P b91cec479d1b43598863d7b15927054cd089f51a385e86a4e511ffef64f6cfad -R 8129360d19ca72d5540a042049a13e26 +P 3cec1488f4f1a375d9c97e073a4fe2e2099113e03a88a401a26e9331c783da86 +R 30833777a1a668ffdffa491e9ac5d3af U larrybr -Z d6535bcd86ae75656b3143470547f39d +Z 5728435be9055029d5aa1c859c1dfc28 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e6cdc5dd74..afa2e36c44 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3cec1488f4f1a375d9c97e073a4fe2e2099113e03a88a401a26e9331c783da86 \ No newline at end of file +243085279c6f8c51ad85bdc1e7c07ef6f858067640a7330f77d0bf94ed11b438 \ No newline at end of file diff --git a/src/resmanage.c b/src/resmanage.c index 9f967df370..40ffe132a0 100644 --- a/src/resmanage.c +++ b/src/resmanage.c @@ -30,8 +30,8 @@ typedef enum FreeableResourceKind { #ifdef SHELL_MANAGE_TEXT FRK_Text, #endif - FRK_AnyRef, - FRK_CustomBase /* series of values for custom freers */ + FRK_AnyRef, FRK_VdtorRef, + FRK_CountOf } FreeableResourceKind; #if defined(_WIN32) || defined(WIN32) @@ -57,8 +57,10 @@ typedef struct ResourceHeld { ShellText *p_text; #endif AnyResourceHolder *p_any_rh; + VirtualDtorNthObject *p_vdfo; } held; - FreeableResourceKind frk; + unsigned short frk; /* a FreeableResourceKind value */ + unsigned short offset; } ResourceHeld; /* The held-resource stack. This is for single-threaded use only. */ @@ -66,15 +68,6 @@ static ResourceHeld *pResHold = 0; static ResourceCount numResHold = 0; static ResourceCount numResAlloc = 0; -/* A small set of custom freers. It is linearly searched, used for -** layered heap-allocated (and other-allocated) data structures, so -** tends to have use limited to where slow things are happening. -*/ -static ResourceCount numCustom = 0; /* number of the set */ -static ResourceCount numCustomAlloc = 0; /* allocated space */ -typedef void (*FreerFunction)(void *); -static FreerFunction *aCustomFreers = 0; /* content of set */ - const char *resmanage_oom_message = "out of memory, aborting"; /* Info recorded in support of quit_moan(...) and stack-ripping */ @@ -144,14 +137,14 @@ static int free_rk( ResourceHeld *pRH ){ case FRK_AnyRef: (pRH->held.p_any_rh->its_freer)(pRH->held.p_any_rh->pAny); break; - default: + case FRK_VdtorRef: { - int ck = pRH->frk - FRK_CustomBase; - assert(ck>=0); - if( ck < numCustom ){ - aCustomFreers[ck]( pRH->held.p_any ); - }else --rv; + VirtualDtorNthObject *po = pRH->held.p_vdfo; + (po->p_its_freer[pRH->offset])(po); } + break; + default: + assert(pRH->frk < FRK_CountOf); } pRH->held.p_any = 0; return rv; @@ -209,7 +202,7 @@ void release_holder(void){ /* Shared resource-stack pushing code */ static void res_hold(void *pv, FreeableResourceKind frk){ - ResourceHeld rh = { pv, frk }; + ResourceHeld rh = { pv, frk, 0 }; if( numResHold == numResAlloc ){ ResourceCount nrn = (ResourceCount)((numResAlloc>>2) + 5); if( !more_holders_try(nrn) ){ @@ -261,29 +254,7 @@ static void text_ref_holder(ShellText *pt){ res_hold(pt, FRK_Text); } #endif -/* Hold anything together with arbitrary freeing function */ -void* any_holder(void *pm, void (*its_freer)(void*)){ - int i = 0; - while( i < numCustom ){ - if( its_freer == aCustomFreers[i] ) break; - ++i; - } - if( i == numCustom ){ - size_t ncf = numCustom + 2; - FreerFunction *pcf; - pcf = (FreerFunction *)realloc(aCustomFreers, ncf*sizeof(FreerFunction)); - if( pcf!=0 ){ - assert(ncf < (1<<16)); - numCustomAlloc = (ResourceCount)ncf; - aCustomFreers = pcf; - aCustomFreers[numCustom++] = its_freer; - }else{ - quit_moan(resmanage_oom_message,1); - } - } - res_hold(pm, i + FRK_CustomBase); - return pm; -} + /* Hold some SQLite-allocated memory */ void* smem_holder(void *pm){ res_hold(pm, FRK_DbMem); @@ -307,6 +278,19 @@ void any_ref_holder(AnyResourceHolder *parh){ assert(parh!=0 && parh->its_freer!=0); res_hold(parh, FRK_AnyRef); } +/* Hold a reference to a VirtualDtorNthObject (in stack frame) */ +void dtor_ref_holder(VirtualDtorNthObject *pvdfo, unsigned char n){ + ResourceHeld rh = { (void*)pvdfo, FRK_VdtorRef, n }; + assert(pvdfo!=0 && pvdfo->p_its_freer!=0 && *(pvdfo->p_its_freer)!=0); + if( numResHold == numResAlloc ){ + ResourceCount nrn = (ResourceCount)((numResAlloc>>2) + 5); + if( !more_holders_try(nrn) ){ + free_rk(&rh); + quit_moan(resmanage_oom_message,1); + } + } + pResHold[numResHold++] = rh; +} /* Free all held resources in excess of given resource stack mark, ** then return how many needed freeing. */ @@ -321,12 +305,6 @@ int holder_free(ResourceMark mark){ pResHold = 0; numResAlloc = 0; } - if( numCustomAlloc>0 ){ - free(aCustomFreers); - aCustomFreers = 0; - numCustom = 0; - numCustomAlloc = 0; - } } return rv; } diff --git a/src/resmanage.h b/src/resmanage.h index f1cd155823..147821c90a 100644 --- a/src/resmanage.h +++ b/src/resmanage.h @@ -97,8 +97,6 @@ extern void release_holder(void); ** The referenced objects are directly freed; they are stored in ** the heap with lifetime not bound to the caller's activation. */ -/* anything together with arbitrary freeing function */ -extern void* any_holder(void *pm, void (*its_freer)(void*)); /* anything in the malloc() heap */ extern void* mmem_holder(void *pm); /* a C string in the malloc() heap */ @@ -126,17 +124,29 @@ extern void pipe_holder(FILE *); ** exits, this condition is met because holder_free() is called ** by the abrupt exiter before the execution stack is stripped. */ + +/* An arbitrary data pointer paired with its freer function */ typedef struct AnyResourceHolder { void *pAny; GenericFreer its_freer; } AnyResourceHolder; +/* An object of a class having its dtor as the Nth v-table entry. +** This is only useful when it is embedded in a bigger object. */ +typedef struct VirtualDtorNthObject VirtualDtorNthObject; +typedef void (*VirtualDtorNth)(VirtualDtorNthObject *); +struct VirtualDtorNthObject { + VirtualDtorNth *p_its_freer; +}; + /* a reference to an AnyResourceHolder (whose storage is not managed) */ extern void any_ref_holder(AnyResourceHolder *parh); /* a C string in the SQLite heap, reference to */ extern void sstr_ptr_holder(char **pz); /* a SQLite prepared statement, reference to */ extern void stmt_ptr_holder(sqlite3_stmt **ppstmt); +/* an object with v-table (ref) whose dtor is the 0th member, reference to */ +extern void dtor_ref_holder(VirtualDtorNthObject *pvdfo, unsigned char n); #ifdef SHELL_MANAGE_TEXT /* a ShellText object, reference to (storage for which not managed) */ static void text_ref_holder(ShellText *); diff --git a/src/shell.c.in b/src/shell.c.in index c9443ca5f6..108ea78d59 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1039,40 +1039,67 @@ static FILE * openChrSource(const char *zFile){ /* ** Arrange for shell input from either a FILE or a string. ** For applicable invariants, see strLineGet(...) which is -** the only modifier of this struct. (3rd and 4th members) +** the only modifier of this struct. (4rd and 5th members) ** All other members are simply initialized to select the ** input stream and track input sources, set by whatever ** routines redirect the input. */ typedef struct InSource { + struct InSource *pFrom; /* Aid redirect tracking and auto-unnesting. */ FILE *inFile; /* Will be 0 when input is to be taken from string. */ char *zStrIn; /* Will be 0 when no input is available from string. */ - int iReadOffset; /* Offset into zStrIn where next "read" to be done. */ + int iReadOffset; /* Offset into zStrIn where next "read" to be done */ int lineno; /* How many lines have been read from this source */ - const char *zSourceSay; /* For complaints, keep a name for this source */ - struct InSource *pFrom; /* and redirect tracking to aid unraveling. */ + const char *zSourceSay; /* For complaints, a name kept for this source */ + union { + int (*stream)(FILE *); + void (*ptext)(char *); + } closer; /* Closer for the file or freer for the text, set by opener */ } InSource; -#define INSOURCE_STR_REDIR(str, tagTo, isFrom) {0, str, 0, 0, tagTo, isFrom} -#define INSOURCE_FILE_REDIR(fh, tagTo, isFrom) {fh, 0, 0, 0, tagTo, isFrom} +#define INSOURCE_STR_REDIR(str, tagTo, isFrom) {isFrom, 0, str, 0, 0, tagTo } +#define INSOURCE_FILE_REDIR(fh, tagTo, isFrom) {isFrom, fh, 0, 0, 0, tagTo } #define INSOURCE_IS_INTERACTIVE(pIS) \ ((pIS)==&termInSource && stdin_is_interactive ) #define INSOURCE_IS_INVOKEARG(pIS) \ ((pIS)==&cmdInSource) -/* This instance's address is taken as part of interactive input test. */ -static InSource termInSource = { 0, 0, 0, 0, "", 0}; -static InSource stdInSource = { 0, 0, 0, 0, "", 0}; -static InSource cmdInSource = { 0, 0, 0, 0, "", 0}; +/* These instances' addresses are taken as part of interactive input test + * or test for other special handling as a command-line argument. */ +static InSource termInSource = { 0, 0, 0, 0, 0, "", 0 }; +static InSource stdInSource = { 0, 0, 0, 0, 0, "", 0 }; +static InSource cmdInSource = { 0, 0, 0, 0, 0, "", 0 }; + +/* Initializer for just above 3 InSource objects */ static void init_std_inputs(FILE *pIn ){ termInSource.inFile = pIn; stdInSource.inFile = pIn; cmdInSource.lineno = 0; } +/* Setup cmdInSource to supply given text as input. */ static void set_invocation_cmd(char *zDo){ cmdInSource.iReadOffset = 0; cmdInSource.zStrIn = zDo; ++cmdInSource.lineno; } +/* Close an InSource object and unlink it from redirect nesting. */ +static void finish_InSource( InSource **ppIS ){ + if( ppIS!=0 && *ppIS!=0 ){ + InSource *pIS = *ppIS; + if( pIS->closer.stream != 0 ){ + if( pIS->inFile != 0 ){ + (pIS->closer.stream)(pIS->inFile); + pIS->inFile = 0; + }else if( pIS->zStrIn != 0 ){ + (pIS->closer.ptext)(pIS->zStrIn); + pIS->zStrIn = 0; + } + } + *ppIS = pIS->pFrom; + pIS->pFrom = 0; + } +} + +/* Similar to fgets(buffer, limit, file) but for InSource holding a string. */ static char *strLineGet(char *zBuf, int ncMax, InSource *pInSrc){ if( pInSrc->inFile!=0 ){ char *zRet = fgets(zBuf, ncMax, pInSrc->inFile ); @@ -5736,6 +5763,7 @@ static unsigned char *readHexDb(ShellInState *psi, int *pnData){ const char *zDbFilename = psi->pAuxDb->zDbFilename; /* Need next two objects only if redirecting input to get the hex. */ InSource inRedir = INSOURCE_FILE_REDIR(0, zDbFilename, psi->pInSource); + AnyResourceHolder arh = { &psi->pInSource, (GenericFreer)finish_InSource }; unsigned int x[16]; char zLine[1000]; if( zDbFilename ){ @@ -5745,6 +5773,8 @@ static unsigned char *readHexDb(ShellInState *psi, int *pnData){ return 0; } psi->pInSource = &inRedir; + inRedir.closer.stream = fclose; + any_ref_holder(&arh); }else{ /* Will read hex DB lines inline from present input, without redirect. */ if( INSOURCE_IS_INTERACTIVE(psi->pInSource) ){ @@ -5762,7 +5792,7 @@ static unsigned char *readHexDb(ShellInState *psi, int *pnData){ n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */ a = sqlite3_malloc( n ? n : 1 ); shell_check_ooms(a); - smem_holder(a); /* offset 0 */ + smem_holder(a); memset(a, 0, n); if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){ utf8_printf(STD_ERR, "invalid pagesize\n"); @@ -5789,12 +5819,8 @@ static unsigned char *readHexDb(ShellInState *psi, int *pnData){ } } *pnData = n; /* Record success and size. */ - swap_held(mark, 0, 0); + pop_holder(); readHexDb_cleanup: - if( psi->pInSource==&inRedir ){ - fclose( inRedir.inFile ); - psi->pInSource = inRedir.pFrom; - } holder_free(mark); return a; @@ -9496,13 +9522,15 @@ DISPATCHABLE_COMMAND( binary 3 2 2 ){ DISPATCHABLE_COMMAND( cd ? 2 2 ){ int rc=0; if( ISS(p)->bSafeMode ) return DCR_AbortError; + else{ #if defined(_WIN32) || defined(WIN32) - wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]); - rc = !SetCurrentDirectoryW(z); - sqlite3_free(z); + wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]); + rc = (z)? !SetCurrentDirectoryW(z) : 1; + sqlite3_free(z); #else - rc = chdir(azArg[1]); + rc = chdir(azArg[1]); #endif + } if( rc ){ utf8_printf(STD_ERR, "Cannot change to directory \"%s\"\n", azArg[1]); rc = 1; @@ -9589,14 +9617,14 @@ DISPATCHABLE_COMMAND( connection ? 1 4 ){ }else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){ int i = azArg[1][0] - '0'; if( psi->pAuxDb != &psi->aAuxDb[i] && i>=0 && iaAuxDb) ){ - psi->pAuxDb->db = DBI(psi); + psi->pAuxDb->db = DBX(p); psi->pAuxDb = &psi->aAuxDb[i]; #if SHELL_DYNAMIC_EXTENSION - if( DBI(psi)!=0 ) notify_subscribers(psi, NK_DbUserVanishing, DBI(psi)); + if( DBX(p)!=0 ) notify_subscribers(psi, NK_DbUserVanishing, DBX(p)); #endif - globalDb = DBI(psi) = psi->pAuxDb->db; + globalDb = DBX(p) = psi->pAuxDb->db; #if SHELL_DYNAMIC_EXTENSION - if( DBI(psi)!=0 ) notify_subscribers(psi, NK_DbUserAppeared, DBI(psi)); + if( DBX(p)!=0 ) notify_subscribers(psi, NK_DbUserAppeared, DBX(p)); #endif psi->pAuxDb->db = 0; } @@ -9639,6 +9667,7 @@ DISPATCHABLE_COMMAND( databases 2 1 0 ){ open_db(p, 0); db = DBX(p); rc = sqlite3_prepare_v2(db, "PRAGMA database_list", -1, &pStmt, 0); + shell_check_nomem(rc); if( rc ){ *pzErr = smprintf("%s\n", sqlite3_errmsg(db)); rc = 1; @@ -14283,9 +14312,11 @@ static DotCmdRC shellEvalText(char *zIn, const char *zName, ShellExState *psx){ ShellInState *psi = ISS(psx); InSource inRedir = INSOURCE_STR_REDIR(zIn, zName, psi->pInSource); + AnyResourceHolder arh = { &psi->pInSource, (GenericFreer)finish_InSource }; psi->pInSource = &inRedir; + any_ref_holder(&arh); rv = process_input(psi); - psi->pInSource = inRedir.pFrom; + release_holder(); return rv; } @@ -14316,9 +14347,10 @@ DISPATCHABLE_COMMAND( eval 3 1 0 ){ DISPATCHABLE_COMMAND( read 3 2 2 ){ DotCmdRC rc = DCR_Ok; + ShellInState *psi = ISS(p); FILE *inUse = 0; int (*fCloser)(FILE *) = 0; - if( ISS(p)->bSafeMode ) return DCR_AbortError; + if( psi->bSafeMode ) return DCR_AbortError; if( azArg[1][0]=='|' ){ #ifdef SQLITE_OMIT_POPEN *pzErr = smprintf("pipes are not supported in this OS\n"); @@ -14341,14 +14373,15 @@ DISPATCHABLE_COMMAND( read 3 2 2 ){ } if( inUse!=0 ){ InSource inSourceRedir - = INSOURCE_FILE_REDIR(inUse, azArg[1], ISS(p)->pInSource); - ISS(p)->pInSource = &inSourceRedir; - rc = process_input(ISS(p)); + = INSOURCE_FILE_REDIR(inUse, azArg[1], psi->pInSource); + AnyResourceHolder arh = { &(psi->pInSource),(GenericFreer)finish_InSource }; + psi->pInSource = &inSourceRedir; + inSourceRedir.closer.stream = fCloser; + any_ref_holder(&arh); + rc = process_input(psi); /* If error(s) occured during process, leave complaining to them. */ if( rc==DCR_Error ) rc = DCR_CmdErred; - assert(fCloser!=0); - fCloser(inUse); - ISS(p)->pInSource = inSourceRedir.pFrom; + release_holder(); } return rc; } @@ -15086,7 +15119,9 @@ static DotCmdRC runDotCommand(DotCommand *pmc, char *azArg[], int nArg, ShellExState *psx){ char *zErr = 0; DotCmdRC dcr = pmc->pMethods->argsCheck(pmc, &zErr, nArg, azArg); + ResourceMark mark = holder_mark(); + sstr_ptr_holder(&zErr); command_prep(ISS(psx)); if( dcr==DCR_Ok ){ dcr = pmc->pMethods->execute(pmc, psx, &zErr, nArg, azArg); @@ -15094,7 +15129,7 @@ static DotCmdRC runDotCommand(DotCommand *pmc, char *azArg[], int nArg, if( dcr!=DCR_Ok ){ dcr = dot_command_errors(zErr, azArg, nArg, dcr, psx); } - sqlite3_free(zErr); + holder_free(mark); command_post(ISS(psx)); return dcr; } @@ -15118,6 +15153,7 @@ static DotCmdRC do_dot_command(char *zLine, ShellExState *psx){ int ncLineIn = strlen30(zLine); u8 bExpVars = SHEXT_VAREXP(ISS(psx)); #endif + RipStackDest dotRipDest = RIP_STACK_DEST_INIT; /* Parse the input line into tokens which are 0-terminated and left in-place. */ @@ -15148,33 +15184,37 @@ static DotCmdRC do_dot_command(char *zLine, ShellExState *psx){ /* Process the input line. If it was empty, do nothing and declare success. * Note that "empty" includes a leading '.' followed by nothing else. */ - if( nArg>0 ){ - int nFound; - DotCommand *pmc = findDotCommand(azArg[0], psx, &nFound); - if( pmc==0 || nFound>1 ){ - if( nFound==0 ){ - dcr = DCR_Unknown; + register_exit_ripper(&dotRipDest); + if( 0==RIP_TO_HERE(dotRipDest) ){ + if( nArg>0 ){ + int nFound; + DotCommand *pmc = findDotCommand(azArg[0], psx, &nFound); + if( pmc==0 || nFound>1 ){ + if( nFound==0 ){ + dcr = DCR_Unknown; #if SHELL_DYNAMIC_EXTENSION - pmc = ISS(psx)->pUnknown; - if( pmc ) dcr = runDotCommand(pmc, azArg, nArg, psx); + pmc = ISS(psx)->pUnknown; + if( pmc ) dcr = runDotCommand(pmc, azArg, nArg, psx); #endif - }else{ - dcr = DCR_Ambiguous; + }else{ + dcr = DCR_Ambiguous; + } + if( dcr > DCR_ArgIxMask ){ + /* Issue error for unknown or inadequately specified dot command. */ + dcr = dot_command_errors(0, azArg, nArg, dcr, psx); + } } - if( dcr > DCR_ArgIxMask ){ - /* Issue error for unknown or inadequately specified dot command. */ - dcr = dot_command_errors(0, azArg, nArg, dcr, psx); + else{ + char *arg0 = azArg[0]; + azArg[0] = (char *)(pmc->pMethods->name(pmc)); + /* Run found command and issue or handle any errors it may report. */ + dcr = runDotCommand(pmc, azArg, nArg, psx); + azArg[0] = arg0; } } - else{ - char *arg0 = azArg[0]; - azArg[0] = (char *)(pmc->pMethods->name(pmc)); - /* Run found command and issue or handle any errors it may report. */ - dcr = runDotCommand(pmc, azArg, nArg, psx); - azArg[0] = arg0; - } + }else{ + dcr = DCR_Abort|DCR_Error; } - #if SHELL_VARIABLE_EXPANSION if( bExpVars ){ /* Free any arguments that are allocated rather than tokenized in place. */ @@ -16016,6 +16056,7 @@ static void process_sqliterc( const char *sqliterc = sqliterc_override; char *zBuf = 0; FILE *inUse; + ResourceMark mark = holder_mark(); if( sqliterc == NULL ){ sqliterc = find_xdg_config(); @@ -16030,27 +16071,31 @@ static void process_sqliterc( zBuf = smprintf("%s/.sqliterc",home_dir); shell_check_ooms(zBuf); sqliterc = zBuf; + sstr_holder(zBuf); } inUse = fopen(sqliterc,"rb"); if( inUse!=0 ){ InSource inSourceRedir = INSOURCE_FILE_REDIR(inUse, sqliterc, psi->pInSource); + AnyResourceHolder arh = { &psi->pInSource, (GenericFreer)finish_InSource }; DotCmdRC rc; psi->pInSource = &inSourceRedir; + inSourceRedir.closer.stream = fclose; if( stdin_is_interactive ){ utf8_printf(STD_ERR,"-- Loading resources from %s\n",sqliterc); } + any_ref_holder(&arh); rc = process_input(psi); - fclose(inUse); - psi->pInSource = inSourceRedir.pFrom; if( rc>DCR_Ok && bail_on_error ){ XSS(psi)->shellAbruptExit = 0x100|((rc>>1)&0x3); } }else if( sqliterc_override!=0 ){ utf8_printf(STD_ERR,"cannot open: \"%s\"\n", sqliterc); - if( bail_on_error ) exit(1); /* Future: Exit shell rather than process. */ + if( bail_on_error ){ + XSS(psi)->shellAbruptExit = 0x102; + } } - sqlite3_free(zBuf); + holder_free(mark); } /*