From e4a38c12050b4bc1ae138f8156c747b2a3af1762 Mon Sep 17 00:00:00 2001 From: wangchen Date: Tue, 5 Aug 2025 16:57:57 +0800 Subject: [PATCH] Add StackOverflow check Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/ICRAPC Signed-off-by: wangchen Change-Id: I2aa498a2c8c8daa5095f223070d24d68e1ff3ce8 --- .../builtins/builtins_proxy_stub_builder.cpp | 40 ++++++++++++++++++- ecmascript/compiler/stub_builder-inl.h | 18 +++++++++ ecmascript/compiler/stub_builder.h | 2 + ecmascript/stubs/runtime_stubs.cpp | 2 + test/moduletest/proxyget/expect_output.txt | 1 + test/moduletest/proxyget/proxyget.js | 14 +++++++ 6 files changed, 75 insertions(+), 2 deletions(-) diff --git a/ecmascript/compiler/builtins/builtins_proxy_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_proxy_stub_builder.cpp index e969261d46..95943e9535 100644 --- a/ecmascript/compiler/builtins/builtins_proxy_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_proxy_stub_builder.cpp @@ -178,7 +178,8 @@ GateRef BuiltinsProxyStubBuilder::GetProperty(GateRef proxy, GateRef key, GateRe { auto env = GetEnvironment(); DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); - Label callExit(env); + Label stackOverflow(env); + Label dispatch(env); Label checkGetTrapResult(env); Label exit(env); Label handlerIsNull(env); @@ -186,6 +187,14 @@ GateRef BuiltinsProxyStubBuilder::GetProperty(GateRef proxy, GateRef key, GateRe Label slowPath(env); Label trapIsCallable(env); Label trapFastPath(env); + BRANCH_UNLIKELY(CheckStackOverflow(glue_), &stackOverflow, &dispatch); + Bind(&stackOverflow); + { + CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(), RTSTUB_ID(ThrowStackOverflowException), {}); + result = Exception(); + Jump(&exit); + } + Bind(&dispatch); GateRef handler = GetHandler(glue_, proxy); BRANCH(TaggedIsNull(handler), &handlerIsNull, &handlerIsNotNull); Bind(&handlerIsNull); @@ -201,6 +210,15 @@ GateRef BuiltinsProxyStubBuilder::GetProperty(GateRef proxy, GateRef key, GateRe GateRef name = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::GET_STRING_INDEX); GateRef trap = GetPropertyByName(glue_, handler, name); + Label isPendingException(env); + Label noPendingException(env); + BRANCH_UNLIKELY(HasPendingException(glue_), &isPendingException, &noPendingException); + Bind(&isPendingException); + { + result = Exception(); + Jump(&exit); + } + Bind(&noPendingException); BRANCH(TaggedIsHeapObject(trap), &trapFastPath, &slowPath); Bind(&trapFastPath); { @@ -236,8 +254,9 @@ GateRef BuiltinsProxyStubBuilder::SetProperty(GateRef proxy, GateRef key, GateRe { auto env = GetEnvironment(); DEFVARIABLE(result, VariableType::JS_ANY(), TaggedTrue()); + Label stackOverflow(env); + Label dispatch(env); Label trapResultIsFalse(env); - Label callExit(env); Label checkSetTrapResult(env); Label exit(env); Label handlerIsNull(env); @@ -245,6 +264,14 @@ GateRef BuiltinsProxyStubBuilder::SetProperty(GateRef proxy, GateRef key, GateRe Label slowPath(env); Label trapIsCallable(env); Label trapFastPath(env); + BRANCH_UNLIKELY(CheckStackOverflow(glue_), &stackOverflow, &dispatch); + Bind(&stackOverflow); + { + CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(), RTSTUB_ID(ThrowStackOverflowException), {}); + result = TaggedFalse(); + Jump(&exit); + } + Bind(&dispatch); GateRef handler = GetHandler(glue_, proxy); BRANCH(TaggedIsNull(handler), &handlerIsNull, &handlerIsNotNull); Bind(&handlerIsNull); @@ -260,6 +287,15 @@ GateRef BuiltinsProxyStubBuilder::SetProperty(GateRef proxy, GateRef key, GateRe GateRef name = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::SET_STRING_INDEX); GateRef trap = GetPropertyByName(glue_, handler, name); + Label isPendingException(env); + Label noPendingException(env); + BRANCH_UNLIKELY(HasPendingException(glue_), &isPendingException, &noPendingException); + Bind(&isPendingException); + { + result = TaggedFalse(); + Jump(&exit); + } + Bind(&noPendingException); BRANCH(TaggedIsHeapObject(trap), &trapFastPath, &slowPath); Bind(&trapFastPath); { diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index 90bf40f9f4..b76621439d 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -55,6 +55,24 @@ inline int StubBuilder::NextVariableId() return env_->NextVariableId(); } +inline GateRef StubBuilder::ReadSp() +{ + return env_->GetBuilder()->ReadSp(); +} + +inline GateRef StubBuilder::CheckStackOverflow(GateRef glue) +{ + GateRef allowCrossThreadExecution = LoadPrimitive(VariableType::BOOL(), glue, + IntPtr(JSThread::GlueData::GetAllowCrossThreadExecutionOffset(env_->IsArch32Bit()))); + GateRef sp = ReadSp(); + GateRef stackLimit = LoadPrimitive(VariableType::INT64(), glue, + IntPtr(JSThread::GlueData::GetStackLimitOffset(env_->IsArch32Bit()))); + return LogicAndBuilder(env_) + .And(BoolNot(allowCrossThreadExecution)) + .And(Int64UnsignedLessThanOrEqual(sp, stackLimit)) + .Done(); +} + inline GateRef StubBuilder::Int8(int8_t value) { return env_->GetBuilder()->Int8(value); diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index a909b492ca..c81326f138 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -132,6 +132,8 @@ public: { globalEnv_ = globalEnv; } + GateRef ReadSp(); + GateRef CheckStackOverflow(GateRef glue); int NextVariableId(); // constant GateRef Int8(int8_t value); diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index 4f213f59f5..2669d3090b 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -2771,6 +2771,8 @@ DEF_RUNTIME_STUBS(ThrowStackOverflowException) // Multi-thread could cause stack-overflow-check failed too, // so check thread here to distinguish it with the actual stack overflow. ecmaVm->CheckThread(); + LOG_ECMA(ERROR) << "Stack overflow! current:" << thread->GetCurrentStackPosition() + << " limit:" << thread->GetStackLimit(); ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle error = factory->GetJSError(ErrorType::RANGE_ERROR, "Stack overflow!", StackCheck::NO); if (LIKELY(!thread->HasPendingException())) { diff --git a/test/moduletest/proxyget/expect_output.txt b/test/moduletest/proxyget/expect_output.txt index 42df7d4f18..d7cc898abf 100644 --- a/test/moduletest/proxyget/expect_output.txt +++ b/test/moduletest/proxyget/expect_output.txt @@ -14,3 +14,4 @@ $99 undefined TypeError: obj is not Callable +RangeError: Stack overflow! diff --git a/test/moduletest/proxyget/proxyget.js b/test/moduletest/proxyget/proxyget.js index 3a7e251e98..a715cb8090 100644 --- a/test/moduletest/proxyget/proxyget.js +++ b/test/moduletest/proxyget/proxyget.js @@ -189,4 +189,18 @@ function test9() } test9(); +function test10() +{ + let target = { a: 1 }; + const handler = {}; + handler.__proto__ = new Proxy(target, handler); + try { + handler.__proto__ = new Proxy(target, handler); + } catch (error) { + assert_equal(error instanceof RangeError, true); + print(error); + } +} +test10(); + test_end(); -- Gitee