From: stephan Date: Mon, 1 Dec 2025 16:28:55 +0000 (+0000) Subject: Relax the name limits on kvvfs dbs. X-Git-Tag: artiphishell~117^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=db94b3c0d7de18be4182e4210b82a2046c4c954f;p=thirdparty%2Fsqlite.git Relax the name limits on kvvfs dbs. FossilOrigin-Name: 9901cf8e4a00ea9a199a3fb54bd58bd66cff4d02c55433d55f2b417e188e49e0 --- diff --git a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js index f96374d31c..025306cf29 100644 --- a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js @@ -278,16 +278,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ Throws if storage name n (JS string) is not valid for use as a storage name. Much of this goes back to kvvfs having a fixed buffer size for its keys, and the storage name needing to be - encoded in the keys for local/session storage. We disallow - non-ASCII to avoid problems with truncated multibyte characters - at the end of the key buffer. + encoded in the keys for local/session storage. The second argument must only be true when called from xOpen() - it makes names with a "-journal" suffix legal. */ const validateStorageName = function(n,mayBeJournal=false){ if( kvvfsIsPersistentName(n) ) return; - const len = n.length; + const len = (new Blob([n])).size/*byte length*/; if( !len ) toss3(capi.SQLITE_RANGE, "Empty name is not permitted."); let maxLen = cache.keySize - 1; if( cache.rxJournalSuffix.test(n) ){ @@ -296,7 +294,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ "Storage names may not have a '-journal' suffix."); } }else{ - maxLen -= 8 /* "-journal" */; + maxLen -= 8 /* so we have space for a matching "-journal" suffix */; } if( len > maxLen ){ toss3(capi.SQLITE_RANGE, "Storage name is too long. Limit =", maxLen); @@ -304,7 +302,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ let i; for( i = 0; i < len; ++i ){ const ch = n.codePointAt(i); - if( ch<43 || ch >126 ){ + if( ch<32 ){ toss3(capi.SQLITE_RANGE, "Illegal character ("+ch+"d) in storage name:",n); } @@ -479,58 +477,64 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'sync': true if it's from xSync(), false if it's from xFileControl(). + + For efficiency's sake, all calls to this function should + be in the form: + + store.listeners && notifyListeners(...); + + Failing to do so will trigger an exceptin in this function (which + will be ignored but may produce a console warning). */ const notifyListeners = async function(eventName,store,...args){ try{ - if( store.listeners ){ - //cache.rxPageNoSuffix ??= /(\d+)$/; - if( store.keyPrefix && args[0] ){ - args[0] = args[0].replace(store.keyPrefix,''); - } - let u8enc, z0, z1, wcache; - for(const ear of store.listeners){ - const ev = Object.create(null); - ev.storageName = store.jzClass; - ev.type = eventName; - const decodePages = ear.decodePages; - const f = ear.events[eventName]; - if( f ){ - if( !ear.includeJournal && args[0]==='jrnl' ){ + //cache.rxPageNoSuffix ??= /(\d+)$/; + if( store.keyPrefix && args[0] ){ + args[0] = args[0].replace(store.keyPrefix,''); + } + let u8enc, z0, z1, wcache; + for(const ear of store.listeners){ + const ev = Object.create(null); + ev.storageName = store.jzClass; + ev.type = eventName; + const decodePages = ear.decodePages; + const f = ear.events[eventName]; + if( f ){ + if( !ear.includeJournal && args[0]==='jrnl' ){ + continue; + } + if( 'write'===eventName && ear.decodePages && +args[0]>0 ){ + /* Decode pages to Uint8Array, caching the result in + wcache in case we have more listeners. */ + ev.data = [args[0]]; + if( wcache?.[args[0]] ){ + ev.data[1] = wcache[args[0]]; continue; } - if( 'write'===eventName && ear.decodePages && +args[0]>0 ){ - /* Decode pages to Uint8Array, caching the result in - wcache in case we have more listeners. */ - ev.data = [args[0]]; - if( wcache?.[args[0]] ){ - ev.data[1] = wcache[args[0]]; - continue; - } - u8enc ??= new TextEncoder('utf-8'); - z0 ??= cache.memBuffer(10); - z1 ??= cache.memBuffer(11); - const u = u8enc.encode(args[1]); - const heap = wasm.heap8u(); - heap.set(u, Number(z0)); - heap[wasm.ptr.addn(z0, u.length)] = 0; - const rc = kvvfsDecode(z0, z1, cache.buffer.n); - if( rc>0 ){ - wcache ??= Object.create(null); - wcache[args[0]] - = ev.data[1] - = heap.slice(Number(z1), wasm.ptr.addn(z1,rc)); - }else{ - continue; - } + u8enc ??= new TextEncoder('utf-8'); + z0 ??= cache.memBuffer(10); + z1 ??= cache.memBuffer(11); + const u = u8enc.encode(args[1]); + const heap = wasm.heap8u(); + heap.set(u, Number(z0)); + heap[wasm.ptr.addn(z0, u.length)] = 0; + const rc = kvvfsDecode(z0, z1, cache.buffer.n); + if( rc>0 ){ + wcache ??= Object.create(null); + wcache[args[0]] + = ev.data[1] + = heap.slice(Number(z1), wasm.ptr.addn(z1,rc)); }else{ - ev.data = args.length - ? ((args.length===1) ? args[0] : args) - : undefined; - } - try{f(ev)?.catch?.(catchForNotify)} - catch(e){ - warn("notifyListeners [",store.jzClass,"]",eventName,e); + continue; } + }else{ + ev.data = args.length + ? ((args.length===1) ? args[0] : args) + : undefined; + } + try{f(ev)?.catch?.(catchForNotify)} + catch(e){ + warn("notifyListeners [",store.jzClass,"]",eventName,e); } } } @@ -772,8 +776,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const jzClass = wasm.cstrToJs(zName); //debug("xOpen",jzClass); validateStorageName(jzClass, true); - util.assert( jzClass.length===wasm.cstrlen(zName), - "ASCII-only validation failed" ); if( (flags & (capi.SQLITE_OPEN_MAIN_DB | capi.SQLITE_OPEN_TEMP_DB | capi.SQLITE_OPEN_TRANSIENT_DB)) diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index c6db797237..e0cb8408fe 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -2978,14 +2978,20 @@ globalThis.sqlite3InitModule = sqlite3InitModule; const DB = sqlite3.oo1.DB; T.mustThrowMatching(()=>{ - new JDb("this is an illegal name too long and spaces"); + new JDb("this\ns an illegal - contains control characters"); /* We don't have a way to get error strings from xOpen() to this point? xOpen() does not have a handle to the db and SQLite is not calling xGetLastError() to fetch the error string. */ }, capi.SQLITE_RANGE); T.mustThrowMatching(()=>{ - new JDb("012345678901234567890123"/*too long*/); + new JDb("01234567890123456789"+ + "01234567890123456789"+ + "01234567890123456789"+ + "01234567890123456789"+ + "01234567890123456789"+ + "01234567890123456789"+ + "0"/*too long*/); }, capi.SQLITE_RANGE); T.mustThrowMatching(()=>new JDb(""), capi.SQLITE_RANGE); { @@ -3074,7 +3080,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule; name: 'concurrent transient kvvfs', //predicate: ()=>false, test: function(sqlite3){ - const filename = 'my'; + const filename = '👷'; const kvvfs = sqlite3.kvvfs; const DB = sqlite3.oo1.DB; const JDb = sqlite3.oo1.JsStorageDb; @@ -3284,6 +3290,12 @@ globalThis.sqlite3InitModule = sqlite3InitModule; includeJournal: pglog.includeJournal, decodePages: pglog.decodePages, events: { + /** + These may be async but must not be in this case + because we can't test their result without a lot of + hoop-jumping if they are. Kvvfs calls these + asynchronously, though. + */ 'open': (ev)=>{ //console.warn('open',ev); incr(ev.type); @@ -3291,8 +3303,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule; .assert('number'===typeof ev.data); }, 'close': (ev)=>{ - //^^^ if this is async, we can't time the test for - // pglog.exception without far more hoop-jumping. //console.warn('close',ev); incr(ev.type); T.assert('number'===typeof ev.data); diff --git a/manifest b/manifest index 0d864feab4..3c08cceb90 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Reformulate\ssqlite3-wasm.c's\sexports\sso\sthat\sthey\sexport\sproperly\swith\sthe\swask-sdk\scompiler. -D 2025-12-01T16:25:53.470 +C Relax\sthe\sname\slimits\son\skvvfs\sdbs. +D 2025-12-01T16:28:55.133 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -600,7 +600,7 @@ F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d -F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 82e29781ab83805c7c82ddfe3b5c8fdbc65a914f1433bf966fd7f0f08c7c7c8b +F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 7b723b492460c1531334b0855f02556b45fc767f0276fe7110f5d651679a8a70 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js a2eea6442556867b589e04107796c6e1d04a472219529eeb45b7cd221d7d048b F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 @@ -647,7 +647,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c F ext/wasm/tester1-worker.c-pp.html 0e432ec2c0d99cd470484337066e8d27e7aee4641d97115338f7d962bf7b081a F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb -F ext/wasm/tester1.c-pp.js f248ff562b75ce1040c8d148d648afce7cad50683f532cac96dd82ccabcf282e +F ext/wasm/tester1.c-pp.js 7506d33282dd3e02437a0e3f2eb477c7ae346099d28d482a74a5b4ee9d4028c5 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88 F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2180,8 +2180,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 104291469169bef0c2ec5aee9c1cc505447541801bc822e6d5fe5360aef6a2e4 -R 53cc160340c8953977c4053fb7d21394 +P d71849958aabdb05225be18d6bc46699cfda9de67c7105b11c3f79d1d01f47d4 +R fd9d654ea19b0109ad238cc31ff79cd0 U stephan -Z 34eeecdc220cc86d4441f67333d1408a +Z 7cd40f087bc8b7facc6511e6b1140591 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5cf8d92eb8..3757218b73 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d71849958aabdb05225be18d6bc46699cfda9de67c7105b11c3f79d1d01f47d4 +9901cf8e4a00ea9a199a3fb54bd58bd66cff4d02c55433d55f2b417e188e49e0