1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-30 21:48:11 +00:00

LibJS: Throw RuntimeError when reaching the end of the stack

This prevents stack overflows when calling infinite/deep recursive
functions, e.g.:

    const f = () => f(); f();
    JSON.stringify({}, () => ({ foo: "bar" }));
    new Proxy({}, { get: (_, __, p) => p.foo }).foo;

The VM caches a StackInfo object to not slow down function calls
considerably. VM::push_call_frame() will throw an exception if
necessary (plain Error with "RuntimeError" as its .name).
This commit is contained in:
Linus Groh 2020-11-08 12:54:52 +00:00 committed by Andreas Kling
parent 9c3ead8f91
commit a02b9983f9
5 changed files with 58 additions and 18 deletions

View file

@ -63,7 +63,8 @@ Interpreter::~Interpreter()
Value Interpreter::run(GlobalObject& global_object, const Program& program)
{
ASSERT(!vm().exception());
auto& vm = this->vm();
ASSERT(!vm.exception());
VM::InterpreterExecutionScope scope(*this);
@ -73,13 +74,12 @@ Value Interpreter::run(GlobalObject& global_object, const Program& program)
global_call_frame.function_name = global_execution_context_name;
global_call_frame.environment = heap().allocate<LexicalEnvironment>(global_object, LexicalEnvironment::EnvironmentRecordType::Global);
global_call_frame.environment->bind_this_value(global_object, &global_object);
ASSERT(!vm.exception());
global_call_frame.is_strict_mode = program.is_strict_mode();
if (vm().exception())
return {};
vm().push_call_frame(global_call_frame);
vm.push_call_frame(global_call_frame, global_object);
ASSERT(!vm.exception());
auto result = program.execute(*this, global_object);
vm().pop_call_frame();
vm.pop_call_frame();
return result;
}