@@ -17331,6 +17331,86 @@ TEST(SetStackLimitInThread) {
1733117331 }
1733217332}
1733317333
17334+ static bool TestStackOverflow(v8::Isolate* isolate) {
17335+ v8::Isolate::Scope isolate_scope(isolate);
17336+ v8::HandleScope scope(isolate);
17337+ LocalContext context(isolate);
17338+ v8::TryCatch try_catch(isolate);
17339+ const char* code =
17340+ "var errored = false;"
17341+ "function fn(...args) {"
17342+ " try { fn(...args); }"
17343+ " catch (e) {"
17344+ // Only trigger GC once the stack is full to speedup the test.
17345+ " if (!errored) {"
17346+ " gc();"
17347+ " errored = true;"
17348+ " }"
17349+ " throw e;"
17350+ " }"
17351+ "}"
17352+ "try {"
17353+ " fn.apply(null, new Array(10).fill(1).map(() => {}));"
17354+ " false;"
17355+ "} catch (e) {"
17356+ " e.name === 'RangeError'" // StackOverflow is a RangeError
17357+ "}";
17358+ Local<Value> value = CompileRun(code);
17359+
17360+ // A StackOverflow error is thrown, without crashing.
17361+ return value->IsTrue();
17362+ }
17363+
17364+ class StackOverflowThread : public v8::base::Thread {
17365+ public:
17366+ explicit StackOverflowThread(int stack_size, int js_stack_size)
17367+ : Thread(Options("StackOverflowThread", stack_size)),
17368+ js_stack_size_(js_stack_size),
17369+ result_(false) {}
17370+
17371+ void Run() override {
17372+ uintptr_t stack_top = v8::base::Stack::GetStackStart();
17373+ // Compute isolate stack limit by js stack size.
17374+ uintptr_t stack_base = stack_top - js_stack_size_;
17375+ v8::Isolate::CreateParams create_params = CreateTestParams();
17376+ v8::Isolate* isolate = v8::Isolate::New(create_params);
17377+ isolate->SetStackLimit(stack_base);
17378+ result_ = TestStackOverflow(isolate);
17379+ isolate->Dispose();
17380+ }
17381+
17382+ int result() { return result_; }
17383+
17384+ private:
17385+ int js_stack_size_;
17386+ bool result_;
17387+ };
17388+
17389+ TEST(SetStackLimitInThreadAndStackOverflow) {
17390+ // Set a small --stack-size flag.
17391+ i::FlagScope<int> f_stack_size(&i::v8_flags.stack_size, 100);
17392+ // Trigger GC aggressively to verify that GC does not crash with stack litmit.
17393+ i::FlagScope<size_t> f_heap_size(&i::v8_flags.max_heap_size, 8);
17394+ i::FlagScope<bool> f_expose_gc(&i::v8_flags.expose_gc, true);
17395+
17396+ // ASAN requires more stack space.
17397+ #ifdef V8_USE_ADDRESS_SANITIZER
17398+ constexpr int stack_size = 32 * v8::internal::MB;
17399+ constexpr int js_stack_size = 2 * v8::internal::MB;
17400+ #else
17401+ constexpr int stack_size = 2 * v8::internal::MB;
17402+ constexpr int js_stack_size = 1 * v8::internal::MB;
17403+ #endif
17404+ // Spawn an Isolate on a thread with larger stack limits than --stack-size.
17405+ StackOverflowThread thread1(stack_size, js_stack_size);
17406+
17407+ CHECK(thread1.Start());
17408+
17409+ thread1.Join();
17410+
17411+ CHECK(thread1.result());
17412+ }
17413+
1733417414THREADED_TEST(GetHeapStatistics) {
1733517415 LocalContext c1;
1733617416 v8::HandleScope scope(c1->GetIsolate());
0 commit comments