1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Remove two features of jaccwabyt which were fundamentally flawed, along with approx. 250 lines of unit tests which heavily relied on them. Thankfully, none of the sqlite3.js-level code used those bits.

FossilOrigin-Name: a190abc307847174f36421eaa3f47ef349c6f84a2bb35857fa64f64bbe722708
This commit is contained in:
stephan
2022-12-05 15:05:46 +00:00
parent cfb66014bc
commit 2582d418d3
5 changed files with 22 additions and 407 deletions

View File

@@ -740,9 +740,6 @@ self.sqlite3InitModule = sqlite3InitModule;
assert(undefined === K.prototype.lookupMember('nope',false)).
assert(k1 instanceof StructType).
assert(StructType.isA(k1)).
assert(K.resolveToInstance(k1.pointer)===k1).
mustThrowMatching(()=>K.resolveToInstance(null,true), /is-not-a my_struct/).
assert(k1 === StructType.instanceForPointer(k1.pointer)).
mustThrowMatching(()=>k1.$ro = 1, /read-only/);
Object.keys(MyStructDef.members).forEach(function(key){
key = K.memberKey(key);
@@ -752,8 +749,7 @@ self.sqlite3InitModule = sqlite3InitModule;
" from "+k1.memoryDump());
});
T.assert('number' === typeof k1.pointer).
mustThrowMatching(()=>k1.pointer = 1, /pointer/).
assert(K.instanceForPointer(k1.pointer) === k1);
mustThrowMatching(()=>k1.pointer = 1, /pointer/);
k1.$p4 = 1; k1.$pP = 2;
T.assert(1 === k1.$p4).assert(2 === k1.$pP);
if(MyStructDef.members.$p8){
@@ -768,22 +764,13 @@ self.sqlite3InitModule = sqlite3InitModule;
assert('number' === typeof k1.$cstr).
assert('A C-string.' === k1.memberToJsString('cstr'));
k1.$pP = k2;
T.assert(k1.$pP === k2);
T.assert(k1.$pP === k2.pointer);
k1.$pP = null/*null is special-cased to 0.*/;
T.assert(0===k1.$pP);
let ptr = k1.pointer;
k1.dispose();
T.assert(undefined === k1.pointer).
assert(undefined === K.instanceForPointer(ptr)).
mustThrowMatching(()=>{k1.$pP=1}, /disposed instance/);
const k3 = new K();
ptr = k3.pointer;
T.assert(k3 === K.instanceForPointer(ptr));
K.disposeAll();
T.assert(ptr).
assert(undefined === k2.pointer).
assert(undefined === k3.pointer).
assert(undefined === K.instanceForPointer(ptr));
}finally{
k1.dispose();
k2.dispose();
@@ -813,10 +800,8 @@ self.sqlite3InitModule = sqlite3InitModule;
assert(wts instanceof WTStruct).
assert(wts instanceof StructType).
assert(StructType.isA(wts)).
assert(wts === StructType.instanceForPointer(wts.pointer));
T.assert(wts.pointer>0).assert(0===wts.$v4).assert(0n===wts.$v8).
assert(0===wts.$ppV).assert(0===wts.$xFunc).
assert(WTStruct.instanceForPointer(wts.pointer) === wts);
assert(wts.pointer>0).assert(0===wts.$v4).assert(0n===wts.$v8).
assert(0===wts.$ppV).assert(0===wts.$xFunc);
const testFunc =
W.xGet('sqlite3_wasm_test_struct'/*name gets mangled in -O3 builds!*/);
let counter = 0;
@@ -825,7 +810,6 @@ self.sqlite3InitModule = sqlite3InitModule;
/*log("This from a JS function called from C, "+
"which itself was called from JS. arg =",arg);*/
++counter;
T.assert(WTStruct.instanceForPointer(arg) === wts);
if(3===counter){
tossQuietly("Testing exception propagation.");
}
@@ -849,7 +833,7 @@ self.sqlite3InitModule = sqlite3InitModule;
testFunc(wts.pointer);
//log("wts.pointer, wts.$ppV",wts.pointer, wts.$ppV);
T.assert(1===counter).assert(20 === wts.$v4).assert(40n === wts.$v8)
.assert(autoResolvePtr ? (wts.$ppV === wts) : (wts.$ppV === wts.pointer))
.assert(wts.$ppV === wts.pointer)
.assert('string' === typeof wts.memberToJsString('cstr'))
.assert(wts.memberToJsString('cstr') === wts.memberToJsString('$cstr'))
.mustThrowMatching(()=>wts.memberToJsString('xFunc'),
@@ -857,279 +841,30 @@ self.sqlite3InitModule = sqlite3InitModule;
;
testFunc(wts.pointer);
T.assert(2===counter).assert(40 === wts.$v4).assert(80n === wts.$v8)
.assert(autoResolvePtr ? (wts.$ppV === wts) : (wts.$ppV === wts.pointer));
.assert(wts.$ppV === wts.pointer);
/** The 3rd call to wtsFunc throw from JS, which is called
from C, which is called from JS. Let's ensure that
that exception propagates back here... */
T.mustThrowMatching(()=>testFunc(wts.pointer),/^Testing/);
W.uninstallFunction(wts.$xFunc);
wts.$xFunc = 0;
if(autoResolvePtr){
wts.$ppV = 0;
T.assert(!wts.$ppV);
//WTStruct.debugFlags(0x03);
wts.$ppV = wts;
T.assert(wts === wts.$ppV)
//WTStruct.debugFlags(0);
}
wts.$ppV = 0;
T.assert(!wts.$ppV);
//WTStruct.debugFlags(0x03);
wts.$ppV = wts;
T.assert(wts.pointer === wts.$ppV)
wts.setMemberCString('cstr', "A C-string.");
T.assert(Array.isArray(wts.ondispose)).
assert(wts.ondispose[0] === wts.$cstr).
assert('A C-string.' === wts.memberToJsString('cstr'));
const ptr = wts.pointer;
wts.dispose();
T.assert(ptr).assert(undefined === wts.pointer).
assert(undefined === WTStruct.instanceForPointer(ptr))
T.assert(ptr).assert(undefined === wts.pointer);
}finally{
wts.dispose();
}
}/*StructBinder*/)
////////////////////////////////////////////////////////////////////
.t('sqlite3.StructBinder part 2', function(sqlite3){
// https://www.sqlite.org/c3ref/vfs.html
// https://www.sqlite.org/c3ref/io_methods.html
const sqlite3_io_methods = capi.sqlite3_io_methods,
sqlite3_vfs = capi.sqlite3_vfs,
sqlite3_file = capi.sqlite3_file;
//log("struct sqlite3_file", sqlite3_file.memberKeys());
//log("struct sqlite3_vfs", sqlite3_vfs.memberKeys());
//log("struct sqlite3_io_methods", sqlite3_io_methods.memberKeys());
const installMethod = function callee(tgt, name, func){
if(1===arguments.length){
return (n,f)=>callee(tgt,n,f);
}
if(!callee.argcProxy){
callee.argcProxy = function(func,sig){
return function(...args){
if(func.length!==arguments.length){
toss("Argument mismatch. Native signature is:",sig);
}
return func.apply(this, args);
}
};
callee.ondisposeRemoveFunc = function(){
if(this.__ondispose){
const who = this;
this.__ondispose.forEach(
(v)=>{
if('number'===typeof v){
try{wasm.uninstallFunction(v)}
catch(e){/*ignore*/}
}else{/*wasm function wrapper property*/
delete who[v];
}
}
);
delete this.__ondispose;
}
};
}/*static init*/
const sigN = tgt.memberSignature(name),
memKey = tgt.memberKey(name);
//log("installMethod",tgt, name, sigN);
if(!tgt.__ondispose){
T.assert(undefined === tgt.ondispose);
tgt.ondispose = [callee.ondisposeRemoveFunc];
tgt.__ondispose = [];
}
const fProxy = callee.argcProxy(func, sigN);
const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
tgt[memKey] = pFunc;
/**
ACHTUNG: function pointer IDs are from a different pool than
allocation IDs, starting at 1 and incrementing in steps of 1,
so if we set tgt[memKey] to those values, we'd very likely
later misinterpret them as plain old pointer addresses unless
unless we use some silly heuristic like "all values <5k are
presumably function pointers," or actually perform a function
lookup on every pointer to first see if it's a function. That
would likely work just fine, but would be kludgy.
It turns out that "all values less than X are functions" is
essentially how it works in wasm: a function pointer is
reported to the client as its index into the
__indirect_function_table.
So... once jaccwabyt can be told how to access the
function table, it could consider all pointer values less
than that table's size to be functions. As "real" pointer
values start much, much higher than the function table size,
that would likely work reasonably well. e.g. the object
pointer address for sqlite3's default VFS is (in this local
setup) 65104, whereas the function table has fewer than 600
entries.
*/
const wrapperKey = '$'+memKey;
tgt[wrapperKey] = fProxy;
tgt.__ondispose.push(pFunc, wrapperKey);
//log("tgt.__ondispose =",tgt.__ondispose);
return (n,f)=>callee(tgt, n, f);
}/*installMethod*/;
const installIOMethods = function instm(iom){
(iom instanceof capi.sqlite3_io_methods) || toss("Invalid argument type.");
if(!instm._requireFileArg){
instm._requireFileArg = function(arg,methodName){
arg = capi.sqlite3_file.resolveToInstance(arg);
if(!arg){
err("sqlite3_io_methods::xClose() was passed a non-sqlite3_file.");
}
return arg;
};
instm._methods = {
// https://sqlite.org/c3ref/io_methods.html
xClose: /*i(P)*/function(f){
/* int (*xClose)(sqlite3_file*) */
log("xClose(",f,")");
if(!(f = instm._requireFileArg(f,'xClose'))) return capi.SQLITE_MISUSE;
f.dispose(/*noting that f has externally-owned memory*/);
return 0;
},
xRead: /*i(Ppij)*/function(f,dest,n,offset){
/* int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst) */
log("xRead(",arguments,")");
if(!(f = instm._requireFileArg(f))) return capi.SQLITE_MISUSE;
wasm.heap8().fill(0, dest + offset, n);
return 0;
},
xWrite: /*i(Ppij)*/function(f,dest,n,offset){
/* int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst) */
log("xWrite(",arguments,")");
if(!(f=instm._requireFileArg(f,'xWrite'))) return capi.SQLITE_MISUSE;
return 0;
},
xTruncate: /*i(Pj)*/function(f){
/* int (*xTruncate)(sqlite3_file*, sqlite3_int64 size) */
log("xTruncate(",arguments,")");
if(!(f=instm._requireFileArg(f,'xTruncate'))) return capi.SQLITE_MISUSE;
return 0;
},
xSync: /*i(Pi)*/function(f){
/* int (*xSync)(sqlite3_file*, int flags) */
log("xSync(",arguments,")");
if(!(f=instm._requireFileArg(f,'xSync'))) return capi.SQLITE_MISUSE;
return 0;
},
xFileSize: /*i(Pp)*/function(f,pSz){
/* int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize) */
log("xFileSize(",arguments,")");
if(!(f=instm._requireFileArg(f,'xFileSize'))) return capi.SQLITE_MISUSE;
wasm.setMemValue(pSz, 0/*file size*/);
return 0;
},
xLock: /*i(Pi)*/function(f){
/* int (*xLock)(sqlite3_file*, int) */
log("xLock(",arguments,")");
if(!(f=instm._requireFileArg(f,'xLock'))) return capi.SQLITE_MISUSE;
return 0;
},
xUnlock: /*i(Pi)*/function(f){
/* int (*xUnlock)(sqlite3_file*, int) */
log("xUnlock(",arguments,")");
if(!(f=instm._requireFileArg(f,'xUnlock'))) return capi.SQLITE_MISUSE;
return 0;
},
xCheckReservedLock: /*i(Pp)*/function(){
/* int (*xCheckReservedLock)(sqlite3_file*, int *pResOut) */
log("xCheckReservedLock(",arguments,")");
return 0;
},
xFileControl: /*i(Pip)*/function(){
/* int (*xFileControl)(sqlite3_file*, int op, void *pArg) */
log("xFileControl(",arguments,")");
return capi.SQLITE_NOTFOUND;
},
xSectorSize: /*i(P)*/function(){
/* int (*xSectorSize)(sqlite3_file*) */
log("xSectorSize(",arguments,")");
return 0/*???*/;
},
xDeviceCharacteristics:/*i(P)*/function(){
/* int (*xDeviceCharacteristics)(sqlite3_file*) */
log("xDeviceCharacteristics(",arguments,")");
return 0;
}
};
}/*static init*/
iom.$iVersion = 1;
Object.keys(instm._methods).forEach(
(k)=>installMethod(iom, k, instm._methods[k])
);
}/*installIOMethods()*/;
const iom = new sqlite3_io_methods, sfile = new sqlite3_file;
const err = console.error.bind(console);
try {
const IOM = sqlite3_io_methods, S3F = sqlite3_file;
//log("iom proto",iom,iom.constructor.prototype);
//log("sfile",sfile,sfile.constructor.prototype);
T.assert(0===sfile.$pMethods).assert(iom.pointer > 0);
//log("iom",iom);
sfile.$pMethods = iom.pointer;
T.assert(iom.pointer === sfile.$pMethods)
.assert(IOM.resolveToInstance(iom))
.assert(undefined ===IOM.resolveToInstance(sfile))
.mustThrow(()=>IOM.resolveToInstance(0,true))
.assert(S3F.resolveToInstance(sfile.pointer))
.assert(undefined===S3F.resolveToInstance(iom))
.assert(iom===IOM.resolveToInstance(sfile.$pMethods));
T.assert(0===iom.$iVersion);
installIOMethods(iom);
T.assert(1===iom.$iVersion);
//log("iom.__ondispose",iom.__ondispose);
T.assert(Array.isArray(iom.__ondispose)).assert(iom.__ondispose.length>10);
}finally{
iom.dispose();
T.assert(undefined === iom.__ondispose);
}
const dVfs = new sqlite3_vfs(capi.sqlite3_vfs_find(null));
try {
const SB = sqlite3.StructBinder;
T.assert(dVfs instanceof SB.StructType)
.assert(dVfs.pointer)
.assert('sqlite3_vfs' === dVfs.structName)
.assert(!!dVfs.structInfo)
.assert(SB.StructType.hasExternalPointer(dVfs))
.assert(dVfs.$iVersion>0)
.assert('number'===typeof dVfs.$zName)
.assert('number'===typeof dVfs.$xSleep)
.assert(wasm.functionEntry(dVfs.$xOpen))
.assert(dVfs.memberIsString('zName'))
.assert(dVfs.memberIsString('$zName'))
.assert(!dVfs.memberIsString('pAppData'))
.mustThrowMatching(()=>dVfs.memberToJsString('xSleep'),
/Invalid member type signature for C-string/)
.mustThrowMatching(()=>dVfs.memberSignature('nope'), /nope is not a mapped/)
.assert('string' === typeof dVfs.memberToJsString('zName'))
.assert(dVfs.memberToJsString('zName')===dVfs.memberToJsString('$zName'))
;
//log("Default VFS: @",dVfs.pointer);
Object.keys(sqlite3_vfs.structInfo.members).forEach(function(mname){
const mk = sqlite3_vfs.memberKey(mname), mbr = sqlite3_vfs.structInfo.members[mname],
addr = dVfs[mk], prefix = 'defaultVfs.'+mname;
if(1===mbr.signature.length){
let sep = '?', val = undefined;
switch(mbr.signature[0]){
// TODO: move this into an accessor, e.g. getPreferredValue(member)
case 'i': case 'j': case 'f': case 'd': sep = '='; val = dVfs[mk]; break
case 'p': case 'P': sep = '@'; val = dVfs[mk]; break;
case 's': sep = '=';
val = dVfs.memberToJsString(mname);
break;
}
//log(prefix, sep, val);
}else{
//log(prefix," = funcptr @",addr, wasm.functionEntry(addr));
}
});
}finally{
dVfs.dispose();
T.assert(undefined===dVfs.pointer);
}
}/*StructBinder part 2*/)
////////////////////////////////////////////////////////////////////
.t('sqlite3.wasm.pstack', function(sqlite3){
const P = wasm.pstack;