diff --git a/runtime/ecma_exceptions.cpp b/runtime/ecma_exceptions.cpp index a1235f48bd37e10cbb7b695b4886137bf702a5b5..b164d32a5b1cc522b66ab968548b3e6a4103bd5c 100644 --- a/runtime/ecma_exceptions.cpp +++ b/runtime/ecma_exceptions.cpp @@ -14,6 +14,7 @@ */ #include "plugins/ecmascript/runtime/ecma_exceptions.h" +#include "macros.h" #include "plugins/ecmascript/runtime/base/error_helper.h" #include "plugins/ecmascript/runtime/js_function.h" #include "plugins/ecmascript/runtime/js_object.h" @@ -41,5 +42,11 @@ void ThrowException(JSThread *thread, const char *name, const char *msg) SetException(jsThread, *factory->GetJSError(base::ErrorType::TYPE_ERROR, msg)); return; } + + if (std::strcmp(name, RANGE_ERROR_STRING) == 0) { + SetException(jsThread, *factory->GetJSError(base::ErrorType::RANGE_ERROR, msg)); + return; + } + UNREACHABLE(); } } // namespace panda::ecmascript diff --git a/runtime/ecma_exceptions.h b/runtime/ecma_exceptions.h index 64435a49a1e62e3f0eeeb70cfda15f69ce63b2a0..e6ca135a085e3c6b47f8e905aa79fdc082365fbf 100644 --- a/runtime/ecma_exceptions.h +++ b/runtime/ecma_exceptions.h @@ -22,6 +22,7 @@ namespace panda::ecmascript { static constexpr const char *TYPE_ERROR_STRING = "Lecma/TypedError;"; static constexpr const char *REFERENCE_ERROR_STRING = "Lecma/ReferenceError;"; +static constexpr const char *RANGE_ERROR_STRING = "Lecma/RangeError;"; void ThrowException(JSThread *thread, const char *name, const char *msg); } // namespace panda::ecmascript diff --git a/runtime/ecma_language_context.cpp b/runtime/ecma_language_context.cpp index 33bb66e953e1a96677f737c1b882ddd89e75f252..3ea79ddacbfdbe59354af26c7e1eec56a59b5366 100644 --- a/runtime/ecma_language_context.cpp +++ b/runtime/ecma_language_context.cpp @@ -19,6 +19,7 @@ #include "plugins/ecmascript/compiler/ecmascript_extensions/ecmascript_environment.h" #include "plugins/ecmascript/runtime/ecma_class_linker_extension.h" #include "plugins/ecmascript/runtime/ecma_exceptions.h" +#include "plugins/ecmascript/runtime/base/error_type.h" #include "plugins/ecmascript/runtime/js_method.h" #include "plugins/ecmascript/runtime/js_object.h" #include "plugins/ecmascript/runtime/js_tagged_value.h" @@ -78,6 +79,12 @@ void EcmaLanguageContext::ThrowException(ManagedThread *thread, const uint8_t *m reinterpret_cast(mutf8_msg)); } +void EcmaLanguageContext::ThrowStackOverflowException(ManagedThread *thread) const +{ + ecmascript::ThrowException(JSThread::Cast(thread), ecmascript::RANGE_ERROR_STRING, + "Maximum call stack size exceeded"); +} + PandaUniquePtr EcmaLanguageContext::CreateITableBuilder() const { return MakePandaUnique(); diff --git a/runtime/ecma_language_context.h b/runtime/ecma_language_context.h index fd698bc879b3fd1c03f600b8010f599fbbd2ef07..a07ca51a0ffa1b5544cb2e6d60554a240e9a6c04 100644 --- a/runtime/ecma_language_context.h +++ b/runtime/ecma_language_context.h @@ -45,6 +45,8 @@ public: void ThrowException(ManagedThread *thread, const uint8_t *mutf8_name, const uint8_t *mutf8_msg) const override; + void ThrowStackOverflowException(ManagedThread *thread) const override; + coretypes::TaggedValue GetInitialTaggedValue() const override { UNREACHABLE(); diff --git a/runtime/interpreter/ecma-interpreter-inl.h b/runtime/interpreter/ecma-interpreter-inl.h index b9e4c7ed00c5756954be6f654449100d2b31c2bd..ab270c912520b287c8bcb1c582006d0e96f56bdc 100644 --- a/runtime/interpreter/ecma-interpreter-inl.h +++ b/runtime/interpreter/ecma-interpreter-inl.h @@ -5,6 +5,7 @@ #ifndef PANDA_ECMASCRIPT_INTERPRETER_INL_H #define PANDA_ECMASCRIPT_INTERPRETER_INL_H +#include "macros.h" #include "plugins/ecmascript/runtime/ecma_string.h" #include "plugins/ecmascript/runtime/interpreter/ecma-interpreter.h" #include "plugins/ecmascript/runtime/interpreter/js_frame-inl.h" @@ -274,6 +275,9 @@ public: /* is_dynamic = */ true, /* is_range= */ false, /* accept_acc= */ false, /* initobj= */ false>(method); + if (UNLIKELY(js_thread->HasPendingException())) { + return; + } ConstantPool *constant_pool = ConstantPool::Cast(js_function->GetConstantPool().GetHeapObject()); JSTaggedValue lexical_env = js_function->GetLexicalEnv(); diff --git a/runtime/js_thread.cpp b/runtime/js_thread.cpp index 8e5ae7de93bb6d39304dc4b1785b7666861a8c39..9b72345c01ce8e3a45061c20db86ab2a4c624137 100644 --- a/runtime/js_thread.cpp +++ b/runtime/js_thread.cpp @@ -30,6 +30,7 @@ JSThread *JSThread::Create(Runtime *runtime, PandaVM *vm) jsThread->InitBuffers(); JSThread::SetCurrent(jsThread); jsThread->NativeCodeBegin(); + jsThread->InitForStackOverflowCheck(STACK_OVERFLOW_RESERVED_SIZE, STACK_OVERFLOW_PROTECTED_SIZE); return jsThread; } diff --git a/tests/runtime/common/CMakeLists.txt b/tests/runtime/common/CMakeLists.txt index 4531ca029c22050bbeec6aa598cb013f3997accf..7fab0061cd7b5a9ba30c1a147b27b055f58862df 100644 --- a/tests/runtime/common/CMakeLists.txt +++ b/tests/runtime/common/CMakeLists.txt @@ -54,6 +54,7 @@ add_subdirectory(newobjdynrange) add_subdirectory(bitwiseop) add_subdirectory(big_file) add_subdirectory(js_arrays) +add_subdirectory(js_infinite_recursion) add_subdirectory(js_typed_arrays) add_subdirectory(dyninstruction) add_subdirectory(throwdyn) diff --git a/tests/runtime/common/js_infinite_recursion/CMakeLists.txt b/tests/runtime/common/js_infinite_recursion/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..832f76eb9ea85af2a67217d7748cc1d78c7331e1 --- /dev/null +++ b/tests/runtime/common/js_infinite_recursion/CMakeLists.txt @@ -0,0 +1,23 @@ +# Huawei Technologies Co.,Ltd. + +set(JS_INFINITE_RECURSION_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/js_infinite_recursion.txt) +set(JS_INFINITE_RECURSION_BIN ${CMAKE_CURRENT_BINARY_DIR}/js_infinite_recursion.abc) +set(JS_INFINITE_RECURSION_PA ${CMAKE_CURRENT_BINARY_DIR}/js_infinite_recursion.pa) +set(JS_INFINITE_RECURSION_JS ${CMAKE_CURRENT_SOURCE_DIR}/js_infinite_recursion.js) +set(JS_INFINITE_RECURSION_VERIFY ${CMAKE_CURRENT_SOURCE_DIR}/verify.sh) + +set(RUNTIME_ARGUMENTS --boot-panda-files=${PANDA_BINARY_ROOT}/pandastdlib/arkstdlib.abc --load-runtimes=\"ecmascript\" --compiler-enable-jit=false --gc-type=stw --run-gc-in-place ${JS_INFINITE_RECURSION_BIN} _GLOBAL::func_main_0) + +add_custom_command( + OUTPUT ${JS_INFINITE_RECURSION_OUTPUT} + COMMENT "running javascript newobjdynrange testcase" + COMMAND ${PANDA_RUN_PREFIX} $ ${JS_INFINITE_RECURSION_JS} --dump-assembly --output ${JS_INFINITE_RECURSION_BIN} > ${JS_INFINITE_RECURSION_PA} + COMMAND rm -f ${JS_INFINITE_RECURSION_OUTPUT} + COMMAND ${PANDA_RUN_PREFIX} $ ${RUNTIME_ARGUMENTS} > ${JS_INFINITE_RECURSION_OUTPUT} + COMMAND bash ${JS_INFINITE_RECURSION_VERIFY} ${JS_INFINITE_RECURSION_OUTPUT} +) +add_custom_target(js_infinite_recursion + DEPENDS ${JS_INFINITE_RECURSION_OUTPUT} ${JS_INFINITE_RECURSION_VERIFY} +) +add_dependencies(js_infinite_recursion es2panda ark) +add_dependencies(ecmascript_common_tests js_infinite_recursion) diff --git a/tests/runtime/common/js_infinite_recursion/js_infinite_recursion.js b/tests/runtime/common/js_infinite_recursion/js_infinite_recursion.js new file mode 100644 index 0000000000000000000000000000000000000000..65a6f2e616764d83eb2ac5d96f80b5142f8d91a8 --- /dev/null +++ b/tests/runtime/common/js_infinite_recursion/js_infinite_recursion.js @@ -0,0 +1,19 @@ +let run = (f) => { + try { + f(); + } catch (e) { + print(e); + } +} + +function f1() {f1();} +let f2 = () => f2(); +function f3() {new f3();} + +run(f1); +run(f2); +run(f3); +run(f1); +run(f2); +run(f3); + diff --git a/tests/runtime/common/js_infinite_recursion/verify.sh b/tests/runtime/common/js_infinite_recursion/verify.sh new file mode 100644 index 0000000000000000000000000000000000000000..2ef48f5da7d75d4f9582893677c6120e92f48f35 --- /dev/null +++ b/tests/runtime/common/js_infinite_recursion/verify.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved. + +set -eo pipefail + +expected="RangeError: Maximum call stack size exceeded +RangeError: Maximum call stack size exceeded +RangeError: Maximum call stack size exceeded +RangeError: Maximum call stack size exceeded +RangeError: Maximum call stack size exceeded +RangeError: Maximum call stack size exceeded" + +actual=$(cat "$1") +if [[ "$actual" == "$expected" ]];then + exit 0; +else + echo -e "expected:"$expected + echo -e "actual:"$actual + echo -e "\033[31mhelloworld test failed\033[0m" + exit 1; +fi