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
31 using namespace panda;
32
33 using namespace panda::ecmascript;
34
35 namespace panda::test {
36 class HandleLeakTest : public BaseTestWithScope<false> {
37 public:
SetUp()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
51 static sigjmp_buf env;
52 static bool segmentFaultFlag = false;
53 class HandleLeakTestManager {
54 public:
ProcessHandleLeakSegmentFault(int sig)55 static void ProcessHandleLeakSegmentFault(int sig)
56 {
57 segmentFaultFlag = true;
58 siglongjmp(env, sig);
59 }
60
RegisterSignal()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
HWTEST_F_L0(HandleLeakTest,HandleLeakCheck)73 HWTEST_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
HWTEST_F_L0(HandleLeakTest,InitializeCheckOneProperty)82 HWTEST_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
HeandleLeakTestCommon(const EcmaVM * instance,JSHandle<TaggedArray> & newArray)97 static 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
HWTEST_F_L0(HandleLeakTest,PartInitializeCheckMoreProperty)112 HWTEST_F_L0(HandleLeakTest, PartInitializeCheckMoreProperty)
113 {
114 EcmaHandleScope scope(thread);
115 JSHandle<JSHClass> arrayClass(thread->GlobalConstants()->GetHandledTaggedArrayClass());
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
HWTEST_F_L0(HandleLeakTest,InitializeCheckMoreProperty)132 HWTEST_F_L0(HandleLeakTest, InitializeCheckMoreProperty)
133 {
134 EcmaHandleScope scope(thread);
135 JSHandle<JSHClass> arrayClass(thread->GlobalConstants()->GetHandledTaggedArrayClass());
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