Skip to content

Commit 2bd436d

Browse files
authored
Fix use-after-free issue with custom functions (#710)
when the same function name is used with multiple arities. ref: GHSA-28hh-pr2h-2w89
1 parent b24e1e6 commit 2bd436d

3 files changed

Lines changed: 12 additions & 2 deletions

File tree

ext/sqlite3/database.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ define_function_with_flags(VALUE self, VALUE name, VALUE flags)
524524

525525
CHECK(ctx->db, status);
526526

527-
rb_hash_aset(rb_iv_get(self, "@functions"), name, block);
527+
rb_ary_push(rb_iv_get(self, "@functions"), block);
528528

529529
return self;
530530
}

lib/sqlite3/database.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def initialize file, options = {}, zvfs = nil
175175
@authorizer = nil
176176
@progress_handler = nil
177177
@collations = {}
178-
@functions = {}
178+
@functions = []
179179
@results_as_hash = options[:results_as_hash]
180180
@readonly = mode & Constants::Open::READONLY != 0
181181
@default_transaction_mode = options[:default_transaction_mode] || :deferred
@@ -398,6 +398,8 @@ def get_first_value(sql, *bind_vars)
398398
# the FunctionProxy#result= method on the +func+ parameter and
399399
# indicate the return value that way.
400400
#
401+
# A reference to the block will be kept for the lifetime of the database object.
402+
#
401403
# Example:
402404
#
403405
# db.create_function( "maim", 1 ) do |func, value|

test/test_database.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,14 @@ def test_define_function
463463
assert_equal 10, called_with
464464
end
465465

466+
def test_redefine_function_with_different_arity_does_not_use_freed_block
467+
@db.define_function("f") { |a| "orig" }
468+
@db.define_function("f") { |a, b| "new" }
469+
GC.start(full_mark: true, immediate_sweep: true)
470+
471+
assert_equal ["orig"], @db.execute("select f(1)").first
472+
end
473+
466474
def test_call_func_arg_type
467475
called_with = nil
468476
@db.define_function("hello") do |b, c, d|

0 commit comments

Comments
 (0)