diff --git a/ext/mini_racer_extension/mini_racer_extension.cc b/ext/mini_racer_extension/mini_racer_extension.cc index 4111437f..5e4329a1 100644 --- a/ext/mini_racer_extension/mini_racer_extension.cc +++ b/ext/mini_racer_extension/mini_racer_extension.cc @@ -127,6 +127,7 @@ typedef struct { Local fun; Local *argv; EvalResult result; + size_t max_memory; } FunctionCall; enum IsolateFlags { @@ -1454,6 +1455,12 @@ nogvl_context_call(void *args) { // terminate ASAP isolate->SetData(DO_TERMINATE, (void*)false); + if (call->max_memory > 0) { + isolate->SetData(MEM_SOFTLIMIT_VALUE, &call->max_memory); + isolate->SetData(MEM_SOFTLIMIT_REACHED, (void*)false); + isolate->AddGCEpilogueCallback(gc_callback); + } + Isolate::Scope isolate_scope(isolate); EscapableHandleScope handle_scope(isolate); TryCatch trycatch(isolate); @@ -1511,6 +1518,13 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) { call_argv = argv + 1; } + call.max_memory = 0; + VALUE mem_softlimit = rb_iv_get(self, "@max_memory"); + if (mem_softlimit != Qnil) { + unsigned long sl_int = NUM2ULONG(mem_softlimit); + call.max_memory = (size_t)sl_int; + } + bool missingFunction = false; { Locker lock(isolate); diff --git a/test/mini_racer_test.rb b/test/mini_racer_test.rb index 9aa4c53d..7ea0659d 100644 --- a/test/mini_racer_test.rb +++ b/test/mini_racer_test.rb @@ -298,6 +298,33 @@ def test_max_memory assert_raises(MiniRacer::V8OutOfMemoryError) { context.eval('let s = 1000; var a = new Array(s); a.fill(0); while(true) {s *= 1.1; let n = new Array(Math.floor(s)); n.fill(0); a = a.concat(n); };') } end + def test_max_memory_for_call + context = MiniRacer::Context.new(max_memory: 200_000_000) + context.eval(<<~JS) + let s; + function memory_test() { + var a = new Array(s); + a.fill(0); + while(true) { + s *= 1.1; + let n = new Array(Math.floor(s)); + n.fill(0); + a = a.concat(n); + if (s > 1000000) { + return; + } + } + } + function set_s(val) { + s = val; + } + JS + context.call('set_s', 1000) + assert_raises(MiniRacer::V8OutOfMemoryError) { context.call('memory_test') } + s = context.eval('s') + assert_operator(s, :>, 100_000) + end + def test_negative_max_memory context = MiniRacer::Context.new(max_memory: -200_000_000) assert_nil(context.instance_variable_get(:@max_memory))