Index: autoconf/tea/win/nmakehlp.c ================================================================== --- autoconf/tea/win/nmakehlp.c +++ autoconf/tea/win/nmakehlp.c @@ -12,17 +12,12 @@ * ---------------------------------------------------------------------------- */ #define _CRT_SECURE_NO_DEPRECATE #include -#define NO_SHLWAPI_GDI -#define NO_SHLWAPI_STREAM -#define NO_SHLWAPI_REG -#include #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") -#pragma comment (lib, "shlwapi.lib") #include #include /* * This library is required for x64 builds with _some_ versions of MSVC @@ -37,19 +32,19 @@ #ifdef _MSC_VER #define snprintf _snprintf #endif - /* protos */ static int CheckForCompilerFeature(const char *option); -static int CheckForLinkerFeature(const char *option); +static int CheckForLinkerFeature(const char **options, int count); static int IsIn(const char *string, const char *substring); static int SubstituteFile(const char *substs, const char *filename); static int QualifyPath(const char *path); -static const char *GetVersionFromFile(const char *filename, const char *match); +static int LocateDependency(const char *keyfile); +static const char *GetVersionFromFile(const char *filename, const char *match, int numdots); static DWORD WINAPI ReadFromPipe(LPVOID args); /* globals */ #define CHUNK 25 @@ -72,10 +67,11 @@ char *argv[]) { char msg[300]; DWORD dwWritten; int chars; + const char *s; /* * Make sure children (cl.exe and link.exe) are kept quiet. */ @@ -100,20 +96,20 @@ &dwWritten, NULL); return 2; } return CheckForCompilerFeature(argv[2]); case 'l': - if (argc != 3) { + if (argc < 3) { chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -l \n" + "usage: %s -l ? ...?\n" "Tests for whether link.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } - return CheckForLinkerFeature(argv[2]); + return CheckForLinkerFeature(&argv[2], argc-2); case 'f': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -f \n" "Find a substring within another\n" @@ -151,12 +147,17 @@ argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 0; } - printf("%s\n", GetVersionFromFile(argv[2], argv[3])); - return 0; + s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0'); + if (s && *s) { + printf("%s\n", s); + return 0; + } else + return 1; /* Version not found. Return non-0 exit code */ + case 'Q': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -Q path\n" "Emit the fully qualified path\n" @@ -164,10 +165,22 @@ WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return QualifyPath(argv[2]); + + case 'L': + if (argc != 3) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -L keypath\n" + "Emit the fully qualified path of directory containing keypath\n" + "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return LocateDependency(argv[2]); } } chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -c|-f|-l|-Q|-s|-V ...\n" "This is a little helper app to equalize shell differences between WinNT and\n" @@ -311,20 +324,22 @@ || strstr(Err.buffer, "D2021") != NULL); } static int CheckForLinkerFeature( - const char *option) + const char **options, + int count) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; - char cmdline[100]; + int i; + char cmdline[255]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); @@ -366,11 +381,15 @@ /* * Append our option for testing. */ - lstrcat(cmdline, option); + for (i = 0; i < count; i++) { + lstrcat(cmdline, " \""); + lstrcat(cmdline, options[i]); + lstrcat(cmdline, "\""); + } ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ @@ -431,11 +450,13 @@ */ return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL || strstr(Out.buffer, "LNK4044") != NULL || - strstr(Err.buffer, "LNK4044") != NULL); + strstr(Err.buffer, "LNK4044") != NULL || + strstr(Out.buffer, "LNK4224") != NULL || + strstr(Err.buffer, "LNK4224") != NULL); } static DWORD WINAPI ReadFromPipe( LPVOID args) @@ -477,11 +498,12 @@ */ static const char * GetVersionFromFile( const char *filename, - const char *match) + const char *match, + int numdots) { size_t cbBuffer = 100; static char szBuffer[100]; char *szResult = NULL; FILE *fp = fopen(filename, "rt"); @@ -495,23 +517,25 @@ LPSTR p, q; p = strstr(szBuffer, match); if (p != NULL) { /* - * Skip to first digit. + * Skip to first digit after the match. */ + p += strlen(match); while (*p && !isdigit(*p)) { ++p; } /* * Find ending whitespace. */ q = p; - while (*q && (isalnum(*q) || *q == '.')) { + while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q) + && (!strchr("ab", q[-1])) || --numdots))) { ++q; } memcpy(szBuffer, p, q - p); szBuffer[q-p] = 0; @@ -617,24 +641,24 @@ } fclose(sp); } /* debug: dump the list */ -#ifdef _DEBUG +#ifndef NDEBUG { int n = 0; list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr, ++n) { fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value); } } #endif - + /* * Run the substitutions over each line of the input */ - + while (fgets(szBuffer, cbBuffer, fp) != NULL) { list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr) { char *m = strstr(szBuffer, p->key); if (m) { @@ -650,17 +674,28 @@ memcpy(szBuffer, szCopy, sizeof(szCopy)); } } printf(szBuffer); } - + list_free(&substPtr); } fclose(fp); return 0; } +BOOL FileExists(LPCTSTR szPath) +{ +#ifndef INVALID_FILE_ATTRIBUTES + #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + DWORD pathAttr = GetFileAttributes(szPath); + return (pathAttr != INVALID_FILE_ATTRIBUTES && + !(pathAttr & FILE_ATTRIBUTE_DIRECTORY)); +} + + /* * QualifyPath -- * * This composes the current working directory with a provided path * and returns the fully qualified and normalized path. @@ -670,20 +705,106 @@ static int QualifyPath( const char *szPath) { char szCwd[MAX_PATH + 1]; - char szTmp[MAX_PATH + 1]; - char *p; - GetCurrentDirectory(MAX_PATH, szCwd); - while ((p = strchr(szPath, '/')) && *p) - *p = '\\'; - PathCombine(szTmp, szCwd, szPath); - PathCanonicalize(szCwd, szTmp); + + GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL); printf("%s\n", szCwd); return 0; } + +/* + * Implements LocateDependency for a single directory. See that command + * for an explanation. + * Returns 0 if found after printing the directory. + * Returns 1 if not found but no errors. + * Returns 2 on any kind of error + * Basically, these are used as exit codes for the process. + */ +static int LocateDependencyHelper(const char *dir, const char *keypath) +{ + HANDLE hSearch; + char path[MAX_PATH+1]; + int dirlen, keylen, ret; + WIN32_FIND_DATA finfo; + + if (dir == NULL || keypath == NULL) + return 2; /* Have no real error reporting mechanism into nmake */ + dirlen = strlen(dir); + if ((dirlen + 3) > sizeof(path)) + return 2; + strncpy(path, dir, dirlen); + strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */ + keylen = strlen(keypath); + +#if 0 /* This function is not available in Visual C++ 6 */ + /* + * Use numerics 0 -> FindExInfoStandard, + * 1 -> FindExSearchLimitToDirectories, + * as these are not defined in Visual C++ 6 + */ + hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0); +#else + hSearch = FindFirstFile(path, &finfo); +#endif + if (hSearch == INVALID_HANDLE_VALUE) + return 1; /* Not found */ + + /* Loop through all subdirs checking if the keypath is under there */ + ret = 1; /* Assume not found */ + do { + int sublen; + /* + * We need to check it is a directory despite the + * FindExSearchLimitToDirectories in the above call. See SDK docs + */ + if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) + continue; + sublen = strlen(finfo.cFileName); + if ((dirlen+1+sublen+1+keylen+1) > sizeof(path)) + continue; /* Path does not fit, assume not matched */ + strncpy(path+dirlen+1, finfo.cFileName, sublen); + path[dirlen+1+sublen] = '\\'; + strncpy(path+dirlen+1+sublen+1, keypath, keylen+1); + if (FileExists(path)) { + /* Found a match, print to stdout */ + path[dirlen+1+sublen] = '\0'; + QualifyPath(path); + ret = 0; + break; + } + } while (FindNextFile(hSearch, &finfo)); + FindClose(hSearch); + return ret; +} + +/* + * LocateDependency -- + * + * Locates a dependency for a package. + * keypath - a relative path within the package directory + * that is used to confirm it is the correct directory. + * The search path for the package directory is currently only + * the parent and grandparent of the current working directory. + * If found, the command prints + * name_DIRPATH= + * and returns 0. If not found, does not print anything and returns 1. + */ +static int LocateDependency(const char *keypath) +{ + int i, ret; + static const char *paths[] = {"..", "..\\..", "..\\..\\.."}; + + for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) { + ret = LocateDependencyHelper(paths[i], keypath); + if (ret == 0) + return ret; + } + return ret; +} + /* * Local variables: * mode: c * c-basic-offset: 4 Index: ext/misc/appendvfs.c ================================================================== --- ext/misc/appendvfs.c +++ ext/misc/appendvfs.c @@ -655,10 +655,11 @@ sqlite3_vfs *pOrig; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; (void)db; pOrig = sqlite3_vfs_find(0); + if( pOrig==0 ) return SQLITE_ERROR; apnd_vfs.iVersion = pOrig->iVersion; apnd_vfs.pAppData = pOrig; apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile); rc = sqlite3_vfs_register(&apnd_vfs, 0); #ifdef APPENDVFS_TEST Index: ext/misc/cksumvfs.c ================================================================== --- ext/misc/cksumvfs.c +++ ext/misc/cksumvfs.c @@ -821,10 +821,11 @@ static int cksmRegisterVfs(void){ int rc = SQLITE_OK; sqlite3_vfs *pOrig; if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK; pOrig = sqlite3_vfs_find(0); + if( pOrig==0 ) return SQLITE_ERROR; cksm_vfs.iVersion = pOrig->iVersion; cksm_vfs.pAppData = pOrig; cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile); rc = sqlite3_vfs_register(&cksm_vfs, 1); if( rc==SQLITE_OK ){ @@ -868,15 +869,12 @@ ){ int rc; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* not used */ rc = cksmRegisterFunc(db, 0, 0); - if( rc==SQLITE_OK ){ - - } if( rc==SQLITE_OK ){ rc = cksmRegisterVfs(); } if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; return rc; } #endif /* !defined(SQLITE_CKSUMVFS_STATIC) */ Index: ext/misc/memvfs.c ================================================================== --- ext/misc/memvfs.c +++ ext/misc/memvfs.c @@ -557,10 +557,11 @@ const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); mem_vfs.pAppData = sqlite3_vfs_find(0); + if( mem_vfs.pAppData==0 ) return SQLITE_ERROR; mem_vfs.szOsFile = sizeof(MemFile); rc = sqlite3_vfs_register(&mem_vfs, 1); #ifdef MEMVFS_TEST if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension((void(*)(void))memvfsRegister); Index: ext/misc/vfslog.c ================================================================== --- ext/misc/vfslog.c +++ ext/misc/vfslog.c @@ -752,8 +752,9 @@ /* ** Register debugvfs as the default VFS for this process. */ int sqlite3_register_vfslog(const char *zArg){ vlog_vfs.pVfs = sqlite3_vfs_find(0); + if( vlog_vfs.pVfs==0 ) return SQLITE_ERROR; vlog_vfs.base.szOsFile = sizeof(VLogFile) + vlog_vfs.pVfs->szOsFile; return sqlite3_vfs_register(&vlog_vfs.base, 1); } Index: ext/misc/vfsstat.c ================================================================== --- ext/misc/vfsstat.c +++ ext/misc/vfsstat.c @@ -804,10 +804,11 @@ const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); vstat_vfs.pVfs = sqlite3_vfs_find(0); + if( vstat_vfs.pVfs==0 ) return SQLITE_ERROR; vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile; rc = sqlite3_vfs_register(&vstat_vfs.base, 1); if( rc==SQLITE_OK ){ rc = vstatRegister(db, pzErrMsg, pApi); if( rc==SQLITE_OK ){ Index: ext/misc/zipfile.c ================================================================== --- ext/misc/zipfile.c +++ ext/misc/zipfile.c @@ -1484,10 +1484,11 @@ ** time(2)). */ static u32 zipfileTime(void){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); u32 ret; + if( pVfs==0 ) return 0; if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){ i64 ms; pVfs->xCurrentTimeInt64(pVfs, &ms); ret = (u32)((ms/1000) - ((i64)24405875 * 8640)); }else{ Index: ext/rbu/rbu.c ================================================================== --- ext/rbu/rbu.c +++ ext/rbu/rbu.c @@ -54,11 +54,11 @@ exit(1); } void report_default_vfs(){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); - fprintf(stdout, "default vfs is \"%s\"\n", pVfs->zName); + fprintf(stdout, "default vfs is \"%s\"\n", pVfs ? pVfs->zName : "NULL"); } void report_rbu_vfs(sqlite3rbu *pRbu){ sqlite3 *db = sqlite3rbu_db(pRbu, 0); if( db ){ Index: src/alter.c ================================================================== --- src/alter.c +++ src/alter.c @@ -1158,17 +1158,17 @@ RenameCtx *pRename, /* Rename context */ const char *zSql, /* SQL statement to edit */ const char *zNew, /* New token text */ int bQuote /* True to always quote token */ ){ - int nNew = sqlite3Strlen30(zNew); - int nSql = sqlite3Strlen30(zSql); + i64 nNew = sqlite3Strlen30(zNew); + i64 nSql = sqlite3Strlen30(zSql); sqlite3 *db = sqlite3_context_db_handle(pCtx); int rc = SQLITE_OK; char *zQuot = 0; char *zOut; - int nQuot = 0; + i64 nQuot = 0; char *zBuf1 = 0; char *zBuf2 = 0; if( zNew ){ /* Set zQuot to point to a buffer containing a quoted copy of the Index: src/func.c ================================================================== --- src/func.c +++ src/func.c @@ -1314,29 +1314,29 @@ int argc, sqlite3_value **argv ){ const unsigned char *zIn; /* Input string */ const unsigned char *zCharSet; /* Set of characters to trim */ - int nIn; /* Number of bytes in input */ + unsigned int nIn; /* Number of bytes in input */ int flags; /* 1: trimleft 2: trimright 3: trim */ int i; /* Loop counter */ - unsigned char *aLen = 0; /* Length of each character in zCharSet */ + unsigned int *aLen = 0; /* Length of each character in zCharSet */ unsigned char **azChar = 0; /* Individual characters in zCharSet */ int nChar; /* Number of characters in zCharSet */ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ return; } zIn = sqlite3_value_text(argv[0]); if( zIn==0 ) return; - nIn = sqlite3_value_bytes(argv[0]); + nIn = (unsigned)sqlite3_value_bytes(argv[0]); assert( zIn==sqlite3_value_text(argv[0]) ); if( argc==1 ){ - static const unsigned char lenOne[] = { 1 }; + static const unsigned lenOne[] = { 1 }; static unsigned char * const azOne[] = { (u8*)" " }; nChar = 1; - aLen = (u8*)lenOne; + aLen = (unsigned*)lenOne; azChar = (unsigned char **)azOne; zCharSet = 0; }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){ return; }else{ @@ -1343,27 +1343,28 @@ const unsigned char *z; for(z=zCharSet, nChar=0; *z; nChar++){ SQLITE_SKIP_UTF8(z); } if( nChar>0 ){ - azChar = contextMalloc(context, ((i64)nChar)*(sizeof(char*)+1)); + azChar = contextMalloc(context, + ((i64)nChar)*(sizeof(char*)+sizeof(unsigned))); if( azChar==0 ){ return; } - aLen = (unsigned char*)&azChar[nChar]; + aLen = (unsigned*)&azChar[nChar]; for(z=zCharSet, nChar=0; *z; nChar++){ azChar[nChar] = (unsigned char *)z; SQLITE_SKIP_UTF8(z); - aLen[nChar] = (u8)(z - azChar[nChar]); + aLen[nChar] = (unsigned)(z - azChar[nChar]); } } } if( nChar>0 ){ flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context)); if( flags & 1 ){ while( nIn>0 ){ - int len = 0; + unsigned int len = 0; for(i=0; i=nChar ) break; @@ -1371,11 +1372,11 @@ nIn -= len; } } if( flags & 2 ){ while( nIn>0 ){ - int len = 0; + unsigned int len = 0; for(i=0; i=nChar ) break; Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -4282,11 +4282,11 @@ case 3: sqlite3WhereTrace = *ptr; break; } break; } -#ifdef SQLITE_DEBUG +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue) ** ** If "id" is an integer between 1 and SQLITE_NTUNE then set the value ** of the id-th tuning parameter to *piValue. If "id" is between -1 ** and -SQLITE_NTUNE, then write the current value of the (-id)-th Index: src/memdb.c ================================================================== --- src/memdb.c +++ src/memdb.c @@ -859,11 +859,13 @@ ** This routine is called when the extension is loaded. ** Register the new VFS. */ int sqlite3MemdbInit(void){ sqlite3_vfs *pLower = sqlite3_vfs_find(0); - unsigned int sz = pLower->szOsFile; + unsigned int sz; + if( NEVER(pLower==0) ) return SQLITE_ERROR; + sz = pLower->szOsFile; memdb_vfs.pAppData = pLower; /* The following conditional can only be true when compiled for ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave ** it in, to be safe, but it is marked as NO_TEST since there ** is no way to reach it under most builds. */ Index: src/os_unix.c ================================================================== --- src/os_unix.c +++ src/os_unix.c @@ -8066,10 +8066,11 @@ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ sqlite3_vfs_register(&aVfs[i], i==0); } unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); +#ifndef SQLITE_OMIT_WAL /* Validate lock assumptions */ assert( SQLITE_SHM_NLOCK==8 ); /* Number of available locks */ assert( UNIX_SHM_BASE==120 ); /* Start of locking area */ /* Locks: ** WRITE UNIX_SHM_BASE 120 @@ -8081,10 +8082,12 @@ ** READ-3 UNIX_SHM_BASE+6 126 ** READ-4 UNIX_SHM_BASE+7 127 ** DMS UNIX_SHM_BASE+8 128 */ assert( UNIX_SHM_DMS==128 ); /* Byte offset of the deadman-switch */ +#endif + return SQLITE_OK; } /* ** Shutdown the operating system interface. Index: src/random.c ================================================================== --- src/random.c +++ src/random.c @@ -74,15 +74,20 @@ ** Nothing in this file or anywhere else in SQLite does any kind of ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random ** number generator) not as an encryption device. */ if( !wsdPrng.isInit ){ + sqlite3_vfs *pVfs = sqlite3_vfs_find(0); int i; char k[256]; wsdPrng.j = 0; wsdPrng.i = 0; - sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k); + if( NEVER(pVfs==0) ){ + memset(k, 0, sizeof(k)); + }else{ + sqlite3OsRandomness(pVfs, 256, k); + } for(i=0; i<256; i++){ wsdPrng.s[i] = (u8)i; } for(i=0; i<256; i++){ wsdPrng.j += wsdPrng.s[i] + k[i]; Index: src/shell.c.in ================================================================== --- src/shell.c.in +++ src/shell.c.in @@ -224,10 +224,11 @@ /* Return the current wall-clock time */ static sqlite3_int64 timeOfDay(void){ static sqlite3_vfs *clockVfs = 0; sqlite3_int64 t; if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); + if( clockVfs==0 ) return 0; /* Never actually happens */ if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ clockVfs->xCurrentTimeInt64(clockVfs, &t); }else{ double r; clockVfs->xCurrentTime(clockVfs, &r); Index: src/vdbesort.c ================================================================== --- src/vdbesort.c +++ src/vdbesort.c @@ -1071,12 +1071,13 @@ int iTask = (pTask - pTask->pSorter->aTask); sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); } static void vdbeSorterRewindDebug(const char *zEvent){ - i64 t; - sqlite3OsCurrentTimeInt64(sqlite3_vfs_find(0), &t); + i64 t = 0; + sqlite3_vfs *pVfs = sqlite3_vfs_find(0); + if( ALWAYS(pVfs) ) sqlite3OsCurrentTimeInt64(pVfs, &t); fprintf(stderr, "%lld:X %s\n", t, zEvent); } static void vdbeSorterPopulateDebug( SortSubtask *pTask, const char *zEvent Index: test/func.test ================================================================== --- test/func.test +++ test/func.test @@ -1108,10 +1108,17 @@ execsql {SELECT typeof(trim(NULL,'xyz'));} } {null} do_test func-22.22 { execsql {SELECT typeof(trim('hello',NULL));} } {null} + +# 2021-06-15 - infinite loop due to unsigned character counter +# overflow, reported by Zimuzo Ezeozue +# +do_execsql_test func-22.23 { + SELECT trim('xyzzy',x'c0808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080'); +} {xyzzy} # This is to test the deprecated sqlite3_aggregate_count() API. # ifcapable deprecated { do_test func-23.1 {