diff options
Diffstat (limited to 'ext/wasm')
-rw-r--r-- | ext/wasm/api/sqlite3-api-glue.c-pp.js | 29 | ||||
-rw-r--r-- | ext/wasm/tester1.c-pp.js | 67 |
2 files changed, 96 insertions, 0 deletions
diff --git a/ext/wasm/api/sqlite3-api-glue.c-pp.js b/ext/wasm/api/sqlite3-api-glue.c-pp.js index ddcf2535f..bcaff7243 100644 --- a/ext/wasm/api/sqlite3-api-glue.c-pp.js +++ b/ext/wasm/api/sqlite3-api-glue.c-pp.js @@ -228,6 +228,31 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }), '*' ]], + /** + 2025-02-03: We do not have a way to automatically clean up + destructors which are automatically converted from JS functions + via the final argument to sqlite3_set_auxdata(). Because of + that, it is strongly recommended that clients use + wasm.installFunction() to create such callbacks, then pass that + pointer to sqlite3_set_auxdata(). Relying on automated + conversions here will lead to leaks of JS/WASM proxy functions + because sqlite3_set_auxdata() is frequently called in UDFs. + + The sqlite3.oo1.DB class's onclose handlers can be used for this + purpose. For example: + + const pAuxDtor = wasm.installFunction('v(p)', function(ptr){ + //free ptr + }); + myDb.onclose = { + after: ()=>{ + wasm.uninstallFunction(pAuxDtor); + } + }; + + Then pass pAuxDtor as the final argument to appropriate + sqlite3_set_auxdata() calls. + */ ["sqlite3_set_auxdata", undefined, [ "sqlite3_context*", "int", "*", new wasm.xWrap.FuncPtrAdapter({ @@ -1047,6 +1072,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'sqlite3_set_authorizer', 'sqlite3_trace_v2', 'sqlite3_update_hook' + /* + We do not yet have a way to clean up automatically-converted + sqlite3_set_auxdata() finalizers. + */ ]) { const x = wasm.exports[name]; if( !x ){ diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index f83ecbd87..880edcec1 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -3437,6 +3437,73 @@ globalThis.sqlite3InitModule = sqlite3InitModule; } } }) + .t({ + /* https://github.com/sqlite/sqlite-wasm/issues/92 */ + name: 'sqlite3_set_auxdata() binding signature', + test: function(sqlite3){ + const db = new sqlite3.oo1.DB(); + const stack = wasm.pstack.pointer; + const pAux = wasm.pstack.alloc(4); + let pAuxDestructed = 0; + const args = []; + const pAuxDtor = wasm.installFunction('v(p)', function(ptr){ + //log("freeing auxdata"); + ++pAuxDestructed; + }); + let pAuxDtorDestructed = false; + db.onclose = { + after: ()=>{ + pAuxDtorDestructed = true; + wasm.uninstallFunction(pAuxDtor); + } + }; + try{ + db.createFunction("auxtest",{ + xFunc: function(pCx, x, y){ + args.push(x); + T.assert(wasm.isPtr(pCx)); + const localAux = capi.sqlite3_get_auxdata(pCx, 0); + if( !localAux ){ + //log("setting auxdata"); + /** + We do not currently an automated way to clean up + auxdata finalizer functions (the 4th argument to + sqlite3_set_auxdata()) which get automatically + converted from JS to WASM. Because of that, relying + on automated conversions for those is not + recommended. Instead, follow the pattern show in + this function: use wasm.installFunction() to create + the function, then pass the resulting function + pointer this function, and cleanup (at some point) + using wasm.uninstallFunction(). + */ + capi.sqlite3_set_auxdata(pCx, 0, pAux, pAuxDtor); + }else{ + /* This is never actually hit in this example and it's + not entirely clear how to cause it to. The point of + this test, however, is to demonstrate that the + finalizer impl gets triggered, so we're not going to + fret over this at the moment. */ + //log("seen auxdata",localAux); + T.assert(pAux===localAux); + } + return x; + } + }); + db.exec([ + "create table t(a);", + "insert into t(a) values(1),(2),(3);", + "select auxtest(a,a), auxtest(a,a) from t order by a" + ]); + }finally{ + db.close(); + wasm.pstack.restore(stack); + } + T.assert(6===args.length); + T.assert(pAuxDestructed>0); + T.assert(pAuxDtorDestructed); + } + }) ;/*end of Bug Reports group*/; //////////////////////////////////////////////////////////////////////// |