diff --git a/ecmascript/base/json_stringifier.cpp b/ecmascript/base/json_stringifier.cpp index b9f117f743cb34f309ec3fe5d4d64a0cb5698881..aaba9b67375f3230de5a579dec24dda3076fdbff 100644 --- a/ecmascript/base/json_stringifier.cpp +++ b/ecmascript/base/json_stringifier.cpp @@ -733,6 +733,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (!enumCache.IsNull()) { JSHandle cache(thread_, enumCache); uint32_t length = cache->GetLength(); + uint32_t dictStart = length; for (uint32_t i = 0; i < length; i++) { JSTaggedValue key = cache->Get(i); if (!key.IsString()) { @@ -753,11 +754,41 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); + if (obj->GetProperties().IsDictionary()) { + dictStart = i; + handleValue_.Update(value); + hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); + break; + } } handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); } + if (dictStart < length) { + propertiesArr = JSHandle(thread_, obj->GetProperties()); + JSHandle nameDic(propertiesArr); + for (uint32_t i = dictStart + 1;i < length; i++) { + JSTaggedValue key = cache->Get(i); + int hashIndex = nameDic->FindEntry(key); + PropertyAttributes attr = nameDic->GetAttributes(hashIndex); + if (!key.IsString() || hashIndex < 0 || !attr.IsEnumerable()) { + continue; + } + handleKey_.Update(key); + JSTaggedValue value = nameDic->GetValue(hashIndex); + if (UNLIKELY(value.IsAccessor())) { + value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), + JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); + } + handleValue_.Update(value); + hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); + } + } return hasContent; } int end = static_cast(jsHclass->NumberOfProps()); @@ -783,6 +814,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); } handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); @@ -808,6 +840,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); jsHclass = JSHandle(thread_, obj->GetJSHClass()); } handleValue_.Update(value); @@ -845,6 +878,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); } handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); @@ -872,10 +906,14 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl JSTaggedValue entryKey = entry.first.GetTaggedValue(); handleKey_.Update(entryKey); int index = nameDic->FindEntry(entryKey); + if (index < 0) { + continue; + } JSTaggedValue value = nameDic->GetValue(index); if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), JSHandle(obj)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false); } handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); @@ -884,6 +922,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl return hasContent; } + bool JsonStringifier::AppendJsonString(const JSHandle &obj, const JSHandle &replacer, bool hasContent) { diff --git a/ecmascript/builtins/builtins_array.cpp b/ecmascript/builtins/builtins_array.cpp index 96fc9b4370641e62bd9d34aaa1b903e0dd81deb8..bb6760735ee8fc7dcddeab20b3b438509785e396 100644 --- a/ecmascript/builtins/builtins_array.cpp +++ b/ecmascript/builtins/builtins_array.cpp @@ -1278,6 +1278,10 @@ JSTaggedValue BuiltinsArray::Join(EcmaRuntimeCallInfo *argv) if (k > 0) { concatStr.append(sepStr); } + if (concatStr.size() > EcmaString::MAX_STRING_LENGTH) { + context->JoinStackPopFastPath(thisHandle); + THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception()); + } concatStr.append(nextStr); } @@ -2586,12 +2590,10 @@ JSTaggedValue BuiltinsArray::ToString(EcmaRuntimeCallInfo *argv) callbackFnHandle = JSTaggedValue::GetProperty(thread, objectPrototype, toStringKey).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } - const uint32_t argsLength = argv->GetArgsNumber(); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo *info = - EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisObjVal, undefined, argsLength); + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisObjVal, undefined, 0); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - info->SetCallArg(argsLength, 0, argv, 0); return JSFunction::Call(info); } diff --git a/ecmascript/builtins/builtins_reflect.cpp b/ecmascript/builtins/builtins_reflect.cpp index 0cd4459a717734a5d708fde7e3144b5cdcbc2016..1c6810efdd7490d2b857749ab859d95c63d627a4 100644 --- a/ecmascript/builtins/builtins_reflect.cpp +++ b/ecmascript/builtins/builtins_reflect.cpp @@ -138,7 +138,6 @@ JSTaggedValue BuiltinsReflect::ReflectGet(EcmaRuntimeCallInfo *argv) if (!val->IsECMAObject()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.get target is not object", JSTaggedValue::Exception()); } - JSHandle target = JSHandle::Cast(val); // 2. Let key be ? ToPropertyKey(propertyKey). JSHandle key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -146,10 +145,10 @@ JSTaggedValue BuiltinsReflect::ReflectGet(EcmaRuntimeCallInfo *argv) // a. Set receiver to target. // 4. Return ? target.[[Get]](key, receiver). if (argv->GetArgsNumber() == 2) { // 2: 2 means that there are 2 args in total - return JSObject::GetProperty(thread, target, key).GetValue().GetTaggedValue(); + return JSTaggedValue::GetProperty(thread, val, key).GetValue().GetTaggedValue(); } JSHandle receiver = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD); - return JSObject::GetProperty(thread, val, key, receiver).GetValue().GetTaggedValue(); + return JSTaggedValue::GetProperty(thread, val, key, receiver).GetValue().GetTaggedValue(); } // ecma 26.1.6 Reflect.getOwnPropertyDescriptor ( target, propertyKey ) diff --git a/ecmascript/builtins/builtins_typedarray.cpp b/ecmascript/builtins/builtins_typedarray.cpp index 774b1ff04ad313148b53511d367249ce075d5f80..785ddb5be5500a23079d9a8d22dc6d444a2f705b 100644 --- a/ecmascript/builtins/builtins_typedarray.cpp +++ b/ecmascript/builtins/builtins_typedarray.cpp @@ -781,7 +781,7 @@ JSTaggedValue BuiltinsTypedArray::Join(EcmaRuntimeCallInfo *argv) const GlobalEnvConstants *globalConst = thread->GlobalConstants(); return globalConst->GetEmptyString(); } - size_t allocateLength = 0; + uint64_t allocateLength = 0; bool isOneByte = (sep != BuiltinsTypedArray::SeparatorFlag::MINUS_ONE) || EcmaStringAccessor(sepStringHandle).IsUtf8(); CVector> vec; @@ -806,7 +806,10 @@ JSTaggedValue BuiltinsTypedArray::Join(EcmaRuntimeCallInfo *argv) vec.push_back(JSHandle(globalConst->GetHandledEmptyString())); } } - allocateLength += sepLength * (length - 1); + allocateLength += static_cast(sepLength) * (length - 1); + if (allocateLength > EcmaString::MAX_STRING_LENGTH) { + THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception()); + } if (allocateLength <= 1) { // sep unused, set isOneByte to default(true) isOneByte = true; diff --git a/ecmascript/builtins/tests/builtins_number_format_test.cpp b/ecmascript/builtins/tests/builtins_number_format_test.cpp index 85dd348bc2934c6b5f5af7660cb3868f9b5ed0a7..8044c7034602c77cedf125370f44dcaeb9c40838 100644 --- a/ecmascript/builtins/tests/builtins_number_format_test.cpp +++ b/ecmascript/builtins/tests/builtins_number_format_test.cpp @@ -86,7 +86,6 @@ HWTEST_F_L0(BuiltinsNumberFormatTest, NumberFormatConstructor) static JSTaggedValue BuiltinsFormatTest(JSThread *thread, JSHandle &options, JSHandle &number, JSHandle &locale) { - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle newTarget(env->GetNumberFormatFunction()); @@ -109,20 +108,13 @@ static JSTaggedValue BuiltinsFormatTest(JSThread *thread, JSHandle &op JSTaggedValue resultFunc = BuiltinsNumberFormat::Format(ecmaRuntimeCallInfo2); JSHandle jsFunction(thread, resultFunc); TestHelper::TearDownFrame(thread, prev); - JSArray *jsArray = - JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject()); - JSHandle jsObject(thread, jsArray); - PropertyDescriptor desc(thread, JSHandle(jsFunction), true, true, true); - JSHandle joinKey(factory->NewFromASCII("join")); - JSArray::DefineOwnProperty(thread, jsObject, joinKey, desc); - auto ecmaRuntimeCallInfo3 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); - ecmaRuntimeCallInfo3->SetFunction(JSTaggedValue::Undefined()); - ecmaRuntimeCallInfo3->SetThis(jsObject.GetTaggedValue()); + ecmaRuntimeCallInfo3->SetFunction(jsFunction.GetTaggedValue()); + ecmaRuntimeCallInfo3->SetThis(jsFunction.GetTaggedValue()); ecmaRuntimeCallInfo3->SetCallArg(0, number.GetTaggedValue()); prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo3); - JSTaggedValue result = BuiltinsArray::ToString(ecmaRuntimeCallInfo3); + JSTaggedValue result = JSFunction::Call(ecmaRuntimeCallInfo3); TestHelper::TearDownFrame(thread, prev); return result; } diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index 0909b13ba164ae92811fe07f1fc304992ea9d803..59b0732a5685678cf90a7624ce6598eafb8a4bce 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -1425,6 +1425,13 @@ inline GateRef StubBuilder::IsInvalidPropertyBox(GateRef obj) return TaggedIsHole(value); } +inline GateRef StubBuilder::IsAccessorPropertyBox(GateRef obj) +{ + GateRef valueOffset = IntPtr(PropertyBox::VALUE_OFFSET); + GateRef value = Load(VariableType::JS_ANY(), obj, valueOffset); + return TaggedIsAccessor(value); +} + inline GateRef StubBuilder::GetValueFromPropertyBox(GateRef obj) { GateRef valueOffset = IntPtr(PropertyBox::VALUE_OFFSET); diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 8096fe58c0fc8b4c68f89fc4afdf7eb2363fc917..d76839a508322083b4eaed29ce46caa6bc81e26b 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -1504,18 +1504,18 @@ GateRef StubBuilder::LoadGlobal(GateRef cell) Label entry(env); env->SubCfgEntry(&entry); Label exit(env); - Label cellIsInvalid(env); Label cellNotInvalid(env); + Label cellNotAccessor(env); DEFVARIABLE(result, VariableType::JS_ANY(), Hole()); - Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid); - Bind(&cellIsInvalid); - { - Jump(&exit); - } + Branch(IsInvalidPropertyBox(cell), &exit, &cellNotInvalid); Bind(&cellNotInvalid); { - result = GetValueFromPropertyBox(cell); - Jump(&exit); + Branch(IsAccessorPropertyBox(cell), &exit, &cellNotAccessor); + Bind(&cellNotAccessor); + { + result = GetValueFromPropertyBox(cell); + Jump(&exit); + } } Bind(&exit); auto ret = *result; @@ -2078,19 +2078,19 @@ GateRef StubBuilder::StoreGlobal(GateRef glue, GateRef value, GateRef cell) Label entry(env); env->SubCfgEntry(&entry); Label exit(env); - Label cellIsInvalid(env); Label cellNotInvalid(env); + Label cellIsNotAccessorData(env); DEFVARIABLE(result, VariableType::JS_ANY(), Hole()); - Branch(IsInvalidPropertyBox(cell), &cellIsInvalid, &cellNotInvalid); - Bind(&cellIsInvalid); - { - Jump(&exit); - } + Branch(IsInvalidPropertyBox(cell), &exit, &cellNotInvalid); Bind(&cellNotInvalid); { - Store(VariableType::JS_ANY(), glue, cell, IntPtr(PropertyBox::VALUE_OFFSET), value); - result = Undefined(); - Jump(&exit); + Branch(IsAccessorPropertyBox(cell), &exit, &cellIsNotAccessorData); + Bind(&cellIsNotAccessorData); + { + Store(VariableType::JS_ANY(), glue, cell, IntPtr(PropertyBox::VALUE_OFFSET), value); + result = Undefined(); + Jump(&exit); + } } Bind(&exit); auto ret = *result; diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 6026f241577c43a8f930e92863137caa28b6dc37..23d4af183cfd411e119bf267e855c32652535368 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -343,6 +343,7 @@ public: GateRef HandlerBaseGetAttrIndex(GateRef attr); GateRef HandlerBaseGetRep(GateRef attr); GateRef IsInvalidPropertyBox(GateRef obj); + GateRef IsAccessorPropertyBox(GateRef obj); GateRef GetValueFromPropertyBox(GateRef obj); void SetValueToPropertyBox(GateRef glue, GateRef obj, GateRef value); GateRef GetTransitionHClass(GateRef obj); diff --git a/ecmascript/js_stable_array.cpp b/ecmascript/js_stable_array.cpp index 780e9106bd2fa20efc640f2bf14a8d1ac3923e25..5694b9ba569132a3c3dcb77a200134f70cc6d05b 100644 --- a/ecmascript/js_stable_array.cpp +++ b/ecmascript/js_stable_array.cpp @@ -245,7 +245,7 @@ JSTaggedValue JSStableArray::Join(JSHandle receiver, EcmaRuntimeCallInf return globalConst->GetEmptyString(); } TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject()); - size_t allocateLength = 0; + uint64_t allocateLength = 0; bool isOneByte = (sep != JSStableArray::SeparatorFlag::MINUS_ONE) || EcmaStringAccessor(sepStringHandle).IsUtf8(); CVector> vec; JSMutableHandle elementHandle(thread, JSTaggedValue::Undefined()); @@ -282,9 +282,14 @@ JSTaggedValue JSStableArray::Join(JSHandle receiver, EcmaRuntimeCallInf } } if (len > 0) { - allocateLength += sepLength * (len - 1); + allocateLength += static_cast(sepLength) * (len - 1); } - auto newString = EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), allocateLength, isOneByte); + if (allocateLength > EcmaString::MAX_STRING_LENGTH) { + context->JoinStackPopFastPath(receiverValue); + THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception()); + } + auto newString = + EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), static_cast(allocateLength), isOneByte); int current = 0; DISALLOW_GARBAGE_COLLECTION; for (uint32_t k = 0; k < len; k++) { diff --git a/test/moduletest/builtins/builtinsreflect.js b/test/moduletest/builtins/builtinsreflect.js index 11517c8856b302fce2182ae498c960f323d59a4c..c0da3afdaee417181e76126b23bedb9c69ba1446 100644 --- a/test/moduletest/builtins/builtinsreflect.js +++ b/test/moduletest/builtins/builtinsreflect.js @@ -30,4 +30,7 @@ Reflect.set(v56, "length", v0) Reflect.set(v55, "length", v0, v56) print("v56.length",v56.length) +let obj = {name:"tom"}; +let pxobj = new Proxy(obj,{}); +print(Reflect.get(pxobj,"name")) print("builtins reflect end"); diff --git a/test/moduletest/builtins/expect_output.txt b/test/moduletest/builtins/expect_output.txt index f6fa46c636b36e7ba80669551083c0ddaa213198..4c1243c3ad09cf0ad716ffef9aac74b9631e23da 100644 --- a/test/moduletest/builtins/expect_output.txt +++ b/test/moduletest/builtins/expect_output.txt @@ -57,4 +57,5 @@ false false builtins reflect start v56.length 102630708 +tom builtins reflect end diff --git a/test/moduletest/jsonstringifier/expect_output.txt b/test/moduletest/jsonstringifier/expect_output.txt index 79df9a2fdccee3c10b5d85b44d0b8f47c105b6f3..e69261c64e8e6055405c8e5a24ea9c83d3210b73 100644 --- a/test/moduletest/jsonstringifier/expect_output.txt +++ b/test/moduletest/jsonstringifier/expect_output.txt @@ -19,3 +19,4 @@ test successful {"a":{}} {"3":3} end JSON.stringify(globalThis) +{"a":"a","b":"b"} diff --git a/test/moduletest/jsonstringifier/jsonstringifier.js b/test/moduletest/jsonstringifier/jsonstringifier.js index 14ad4e99e049e1ec6644b838c8ebaaba1e4fafab..5cacdd8ba57a37afbc23a7645f8a3bc68603edd5 100644 --- a/test/moduletest/jsonstringifier/jsonstringifier.js +++ b/test/moduletest/jsonstringifier/jsonstringifier.js @@ -95,3 +95,13 @@ Reflect.defineProperty(globalThis,"c",{ Reflect.set(globalThis,"d","d"); JSON.stringify(globalThis); print("end JSON.stringify(globalThis)") +let obj1 = { + get a(){ + this[102400] = 1; + return "a"; + }, + b:"b", +} +Object.keys(obj1); +print(JSON.stringify(obj1)); + \ No newline at end of file diff --git a/test/moduletest/loadicbyname/expect_output.txt b/test/moduletest/loadicbyname/expect_output.txt index fbdfa11ba31472a8ff83d9c0d12003c90734bdd2..ace947179c212391c3afe48433acf19c4bd2b2d1 100644 --- a/test/moduletest/loadicbyname/expect_output.txt +++ b/test/moduletest/loadicbyname/expect_output.txt @@ -12,3 +12,6 @@ # limitations under the License. false +1 +1 +load global ic with accessor success! diff --git a/test/moduletest/loadicbyname/loadicbyname.js b/test/moduletest/loadicbyname/loadicbyname.js index 2a657ae0c3477a6f71143d85626268b6da9ca340..94e9af31f54a0ad8e02e0fe0cacbc54b383e44c9 100644 --- a/test/moduletest/loadicbyname/loadicbyname.js +++ b/test/moduletest/loadicbyname/loadicbyname.js @@ -45,4 +45,13 @@ try { } catch (e) { flag1 = true; } -print(flag1); \ No newline at end of file +print(flag1); +function f(){return 1}; +Object.defineProperty(this,"g",{ + get:f, + set:f, +}) +for(let i=0;i<2;i++){ + print(g) +} +print("load global ic with accessor success!");