Skip to content

Commit f1565b9

Browse files
Fix use-after-free in JS::Object#call for to_js'ed arg and method values
1 parent b1147f1 commit f1565b9

File tree

2 files changed

+20
-3
lines changed

2 files changed

+20
-3
lines changed

ext/js/js-core.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,23 +257,30 @@ static VALUE _rb_js_obj_call(int argc, VALUE *argv, VALUE obj) {
257257
abi_args.ptr =
258258
ALLOCA_N(rb_js_abi_host_js_abi_value_t, function_arguments_count);
259259
abi_args.len = function_arguments_count;
260+
VALUE rv_args = rb_ary_new2(function_arguments_count);
261+
260262
for (int i = 1; i < argc; i++) {
261263
VALUE arg = _rb_js_try_convert(rb_mJS, argv[i]);
262264
if (arg == Qnil) {
263265
rb_raise(rb_eTypeError, "argument %d is not a JS::Object like object",
264266
1 + i);
265267
}
266268
abi_args.ptr[i - 1] = check_jsvalue(arg)->abi;
269+
rb_ary_push(rv_args, arg);
267270
}
268271

269272
if (rb_block_given_p()) {
270273
VALUE proc = rb_block_proc();
271-
abi_args.ptr[function_arguments_count - 1] =
272-
check_jsvalue(_rb_js_try_convert(rb_mJS, proc))->abi;
274+
VALUE rb_proc = _rb_js_try_convert(rb_mJS, proc);
275+
abi_args.ptr[function_arguments_count - 1] = check_jsvalue(rb_proc)->abi;
276+
rb_ary_push(rv_args, rb_proc);
273277
}
274278

275-
return jsvalue_s_new(
279+
VALUE result = jsvalue_s_new(
276280
rb_js_abi_host_reflect_apply(abi_method->abi, p->abi, &abi_args));
281+
RB_GC_GUARD(rv_args);
282+
RB_GC_GUARD(method);
283+
return result;
277284
}
278285

279286
/*

packages/npm-packages/ruby-wasm-wasi/test/unit/test_object.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,16 @@ def test_call
146146
assert_equal "1,2,3", JS.global.call(:Array, 1, 2, 3).to_s
147147
end
148148

149+
def test_call_with_stress_gc
150+
obj = JS.eval(<<~JS)
151+
return { takeArg() {} }
152+
JS
153+
GC.stress = true
154+
obj.call(:takeArg, "1")
155+
obj.call(:takeArg) {}
156+
GC.stress = false
157+
end
158+
149159
def test_method_missing
150160
assert_equal "42", JS.eval("return 42;").toString.to_s
151161
assert_equal "o", JS.eval("return 'hello';").charAt(4).to_s

0 commit comments

Comments
 (0)