Skip to content

Commit f63e05c

Browse files
authored
Merge pull request sql-js#283 from ShapovalovKL/master
fix function pointer leak
2 parents be04bc1 + 10ab84e commit f63e05c

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed

src/api.coffee

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ class Database
244244
@db = getValue(apiTemp, 'i32')
245245
RegisterExtensionFunctions(@db)
246246
@statements = {} # A list of all prepared statements of the database
247+
@functions = {} # A list of all user function of the database (created by create_function call)
247248

248249
### Execute an SQL query, ignoring the rows it returns.
249250
@@ -395,6 +396,8 @@ class Database
395396
###
396397
'export': ->
397398
stmt['free']() for _,stmt of @statements
399+
removeFunction(func) for _,func of @functions
400+
@functions={}
398401
@handleError sqlite3_close_v2 @db
399402
binaryDb = FS.readFile @filename, encoding:'binary'
400403
@handleError sqlite3_open @filename, apiTemp
@@ -414,6 +417,8 @@ class Database
414417
###
415418
'close': ->
416419
stmt['free']() for _,stmt of @statements
420+
removeFunction(func) for _,func of @functions
421+
@functions={}
417422
@handleError sqlite3_close_v2 @db
418423
FS.unlink '/' + @filename
419424
@db = null
@@ -478,8 +483,11 @@ class Database
478483
switch typeof(result)
479484
when 'number' then sqlite3_result_double(cx, result)
480485
when 'string' then sqlite3_result_text(cx, result, -1, -1)
481-
486+
if(name of @functions)
487+
removeFunction(@functions[name])
488+
delete @functions[name]
482489
# Generate a pointer to the wrapped, user defined function, and register with SQLite.
483490
func_ptr = addFunction(wrapped_func)
491+
@functions[name]=func_ptr
484492
@handleError sqlite3_create_function_v2 @db, name, func.length, SQLite.UTF8, 0, func_ptr, 0, 0, 0
485493
return @

test/test_functions_recreate.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
exports.test = function(sql, assert) {
2+
// Test 1: Create a database, Register single function, close database, repeat 1000 times
3+
4+
for (var i = 1; i <= 1000; i++)
5+
{
6+
let lastStep=(i==1000);
7+
let db = new sql.Database();
8+
function add() {return i;}
9+
try
10+
{
11+
db.create_function("TestFunction"+i, add)
12+
}catch(e)
13+
{
14+
assert.ok(false,"Test 1: Recreate database "+i+"th times and register function failed with exception:"+e);
15+
db.close();
16+
break;
17+
}
18+
var result = db.exec("SELECT TestFunction"+i+"()");
19+
var result_str = result[0]["values"][0][0];
20+
if((result_str!=i)||lastStep)
21+
{
22+
assert.equal(result_str, i, "Test 1: Recreate database "+i+"th times and register function");
23+
db.close();
24+
break;
25+
}
26+
db.close();
27+
}
28+
29+
// Test 2: Create a database, Register same function 1000 times, close database
30+
{
31+
let db = new sql.Database();
32+
for (var i = 1; i <= 1000; i++)
33+
{
34+
let lastStep=(i==1000);
35+
function add() {return i;}
36+
try
37+
{
38+
db.create_function("TestFunction", add);
39+
}catch(e)
40+
{
41+
assert.ok(false,"Test 2: Reregister function "+i+"th times failed with exception:"+e);
42+
break;
43+
}
44+
var result = db.exec("SELECT TestFunction()");
45+
var result_str = result[0]["values"][0][0];
46+
if((result_str!=i)||lastStep)
47+
{
48+
assert.equal(result_str, i, "Test 2: Reregister function "+i+"th times");
49+
break;
50+
}
51+
}
52+
db.close();
53+
}
54+
};
55+
56+
57+
if (module == require.main) {
58+
const target_file = process.argv[2];
59+
const sql_loader = require('./load_sql_lib');
60+
sql_loader(target_file).then((sql)=>{
61+
require('test').run({
62+
'test creating multiple functions': function(assert){
63+
exports.test(sql, assert);
64+
}
65+
});
66+
})
67+
.catch((e)=>{
68+
console.error(e);
69+
assert.fail(e);
70+
});
71+
}

0 commit comments

Comments
 (0)