@@ -17173,6 +17173,86 @@ TEST(SetStackLimitInThread) {
1717317173 }
1717417174}
1717517175
17176+ static bool TestStackOverflow(v8::Isolate* isolate) {
17177+ v8::Isolate::Scope isolate_scope(isolate);
17178+ v8::HandleScope scope(isolate);
17179+ LocalContext context(isolate);
17180+ v8::TryCatch try_catch(isolate);
17181+ const char* code =
17182+ "var errored = false;"
17183+ "function fn(...args) {"
17184+ " try { fn(...args); }"
17185+ " catch (e) {"
17186+ // Only trigger GC once the stack is full to speedup the test.
17187+ " if (!errored) {"
17188+ " gc();"
17189+ " errored = true;"
17190+ " }"
17191+ " throw e;"
17192+ " }"
17193+ "}"
17194+ "try {"
17195+ " fn.apply(null, new Array(10).fill(1).map(() => {}));"
17196+ " false;"
17197+ "} catch (e) {"
17198+ " e.name === 'RangeError'" // StackOverflow is a RangeError
17199+ "}";
17200+ Local<Value> value = CompileRun(code);
17201+
17202+ // A StackOverflow error is thrown, without crashing.
17203+ return value->IsTrue();
17204+ }
17205+
17206+ class StackOverflowThread : public v8::base::Thread {
17207+ public:
17208+ explicit StackOverflowThread(int stack_size, int js_stack_size)
17209+ : Thread(Options("StackOverflowThread", stack_size)),
17210+ js_stack_size_(js_stack_size),
17211+ result_(false) {}
17212+
17213+ void Run() override {
17214+ uintptr_t stack_top = v8::base::Stack::GetStackStart();
17215+ // Compute isolate stack limit by js stack size.
17216+ uintptr_t stack_base = stack_top - js_stack_size_;
17217+ v8::Isolate::CreateParams create_params = CreateTestParams();
17218+ v8::Isolate* isolate = v8::Isolate::New(create_params);
17219+ isolate->SetStackLimit(stack_base);
17220+ result_ = TestStackOverflow(isolate);
17221+ isolate->Dispose();
17222+ }
17223+
17224+ int result() { return result_; }
17225+
17226+ private:
17227+ int js_stack_size_;
17228+ bool result_;
17229+ };
17230+
17231+ TEST(SetStackLimitInThreadAndStackOverflow) {
17232+ // Set a small --stack-size flag.
17233+ i::FlagScope<int> f_stack_size(&i::v8_flags.stack_size, 100);
17234+ // Trigger GC aggressively to verify that GC does not crash with stack litmit.
17235+ i::FlagScope<size_t> f_heap_size(&i::v8_flags.max_heap_size, 8);
17236+ i::FlagScope<bool> f_expose_gc(&i::v8_flags.expose_gc, true);
17237+
17238+ // ASAN requires more stack space.
17239+ #ifdef V8_USE_ADDRESS_SANITIZER
17240+ constexpr int stack_size = 32 * v8::internal::MB;
17241+ constexpr int js_stack_size = 2 * v8::internal::MB;
17242+ #else
17243+ constexpr int stack_size = 2 * v8::internal::MB;
17244+ constexpr int js_stack_size = 1 * v8::internal::MB;
17245+ #endif
17246+ // Spawn an Isolate on a thread with larger stack limits than --stack-size.
17247+ StackOverflowThread thread1(stack_size, js_stack_size);
17248+
17249+ CHECK(thread1.Start());
17250+
17251+ thread1.Join();
17252+
17253+ CHECK(thread1.result());
17254+ }
17255+
1717617256THREADED_TEST(GetHeapStatistics) {
1717717257 LocalContext c1;
1717817258 v8::HandleScope scope(c1->GetIsolate());
0 commit comments