1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include <csetjmp> 17#include <csignal> 18 19#include "ecmascript/ecma_handle_scope.h" 20#include "ecmascript/global_env.h" 21#include "ecmascript/js_tagged_value.h" 22#include "ecmascript/jspandafile/program_object.h" 23#include "ecmascript/mem/barriers.h" 24#include "ecmascript/mem/heap-inl.h" 25#include "ecmascript/mem/verification.h" 26#include "ecmascript/napi/include/jsnapi.h" 27#include "ecmascript/tagged_array.h" 28#include "ecmascript/tests/test_helper.h" 29#include "gtest/gtest.h" 30 31using namespace panda; 32 33using namespace panda::ecmascript; 34 35namespace panda::test { 36class HandleLeakTest : public BaseTestWithScope<false> { 37public: 38 void SetUp() override 39 { 40 JSRuntimeOptions options; 41 options.SetEnableForceGC(false); 42 options.SetLogLevel("info"); 43 instance = JSNApi::CreateEcmaVM(options); 44 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; 45 thread = instance->GetJSThread(); 46 thread->ManagedCodeBegin(); 47 scope = new EcmaHandleScope(thread); 48 } 49}; 50 51static sigjmp_buf env; 52static bool segmentFaultFlag = false; 53class HandleLeakTestManager { 54public: 55 static void ProcessHandleLeakSegmentFault(int sig) 56 { 57 segmentFaultFlag = true; 58 siglongjmp(env, sig); 59 } 60 61 static int RegisterSignal() 62 { 63 segmentFaultFlag = false; 64 struct sigaction act; 65 act.sa_handler = ProcessHandleLeakSegmentFault; 66 sigemptyset(&act.sa_mask); 67 sigaddset(&act.sa_mask, SIGQUIT); 68 act.sa_flags = SA_RESETHAND; 69 return sigaction(SIGSEGV, &act, nullptr); 70 } 71}; 72 73HWTEST_F_L0(HandleLeakTest, HandleLeakCheck) 74{ 75 EcmaHandleScope scope(thread); 76 std::vector<Global<ArrayRef>> result; 77 for (int i = 0; i < 75000; i++) { 78 result.emplace_back(Global<ArrayRef>(instance, ArrayRef::New(instance, 100))); 79 } 80} 81 82HWTEST_F_L0(HandleLeakTest, InitializeCheckOneProperty) 83{ 84 EcmaHandleScope scope(thread); 85 JSHandle<Program> newProgram(thread, const_cast<Heap *>(instance->GetHeap())->AllocateYoungOrHugeObject( 86 JSHClass::Cast(thread->GlobalConstants()->GetProgramClass().GetTaggedObject()))); 87 88 newProgram->SetMainFunction(thread, JSTaggedValue::Undefined()); 89 90 size_t failCount = 0; 91 VerifyObjectVisitor verifier(instance->GetHeap(), &failCount); 92 verifier(*newProgram); 93 ASSERT_TRUE(newProgram.GetTaggedValue().IsProgram()); 94 ASSERT_TRUE(failCount == 0); 95} 96 97static void HeandleLeakTestCommon(const EcmaVM *instance, JSHandle<TaggedArray>& newArray) 98{ 99 size_t failCount = 0; 100 auto ret = sigsetjmp(env, 1); 101 if (ret != SIGSEGV) { 102 VerifyObjectVisitor verifier(instance->GetHeap(), &failCount); 103 verifier(*newArray); 104 ASSERT_TRUE(false); 105 } else { 106 // catch signal SIGSEGV caused by uninitialize 107 EXPECT_TRUE(segmentFaultFlag); 108 ASSERT_TRUE(failCount == 0); 109 } 110} 111 112HWTEST_F_L0(HandleLeakTest, PartInitializeCheckMoreProperty) 113{ 114 EcmaHandleScope scope(thread); 115 JSHandle<JSHClass> arrayClass(thread->GlobalConstants()->GetHandledArrayClass()); 116 static constexpr int SIZE = 100; 117 JSHandle<TaggedArray> newArray(thread, const_cast<Heap *>(instance->GetHeap())->AllocateNonMovableOrHugeObject( 118 *arrayClass, TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), SIZE))); 119 newArray->SetLength(SIZE); 120 for (uint32_t i = 0; i < SIZE / 2; i++) { 121 size_t offset = JSTaggedValue::TaggedTypeSize() * i; 122 ecmascript::Barriers::SetPrimitive(newArray->GetData(), offset, JSTaggedValue::Undefined()); 123 } 124 125 if (HandleLeakTestManager::RegisterSignal() == -1) { 126 perror("sigaction error"); 127 exit(1); 128 } 129 HeandleLeakTestCommon(instance, newArray); 130} 131 132HWTEST_F_L0(HandleLeakTest, InitializeCheckMoreProperty) 133{ 134 EcmaHandleScope scope(thread); 135 JSHandle<JSHClass> arrayClass(thread->GlobalConstants()->GetHandledArrayClass()); 136 static constexpr int SIZE = 100; 137 JSHandle<TaggedArray> newArray(thread, const_cast<Heap *>(instance->GetHeap())->AllocateNonMovableOrHugeObject( 138 *arrayClass, TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), SIZE))); 139 140 newArray->InitializeWithSpecialValue(JSTaggedValue::Hole(), SIZE); 141 size_t failCount = 0; 142 VerifyObjectVisitor verifier(instance->GetHeap(), &failCount); 143 verifier(*newArray); 144 ASSERT_TRUE(newArray.GetTaggedValue().IsTaggedArray()); 145 ASSERT_TRUE(failCount == 0); 146} 147} // namespace panda::test 148