• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "ecmascript/ecma_vm.h"
17 #include "ecmascript/global_env.h"
18 #include "ecmascript/js_handle.h"
19 #include "ecmascript/js_runtime_options.h"
20 #include "ecmascript/log_wrapper.h"
21 #include "ecmascript/mem/concurrent_marker.h"
22 #include "ecmascript/mem/space.h"
23 #include "ecmascript/mem/verification.h"
24 #include "ecmascript/object_factory.h"
25 #include "ecmascript/tagged_array-inl.h"
26 #include "ecmascript/tests/test_helper.h"
27 #include "../runtime_core/common_interfaces/base_runtime.h"
28 #include "common_components/heap/heap_manager.h"
29 #include <csetjmp>
30 #include <csignal>
31 #include <sys/syscall.h>
32 using namespace panda::ecmascript;
33 
34 namespace panda::test {
35 class ReadOnlySpaceTest : public BaseTestWithScope<false> {
36 public:
SetUp()37     void SetUp() override
38     {
39         InitializeLogger();
40         TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
41         factory = thread->GetEcmaVM()->GetFactory();
42         const_cast<panda::ecmascript::Heap *>(thread->GetEcmaVM()->GetHeap())->SetMarkType(MarkType::MARK_FULL);
43     }
44 
InitializeLogger()45     void InitializeLogger()
46     {
47         panda::ecmascript::JSRuntimeOptions runtimeOptions;
48         runtimeOptions.SetLogLevel("error");
49         common::Log::Initialize(runtimeOptions.GetLogOptions());
50     }
51 
52     ObjectFactory *factory {nullptr};
53 };
54 
55 static sigjmp_buf g_env;
56 static bool g_segmentfault_flag = false;
57 class ReadOnlyTestManager {
58 public:
59     // static constexpr int RO_SEGMENTFAULT = 1;
ProcessReadOnlySegmentFault(int sig)60     static void ProcessReadOnlySegmentFault(int sig)
61     {
62         g_segmentfault_flag = true;
63         siglongjmp(g_env, sig);
64     }
65 
RegisterSignal()66     static int RegisterSignal()
67     {
68         struct sigaction act;
69         act.sa_handler = ProcessReadOnlySegmentFault;
70         sigemptyset(&act.sa_mask);
71         sigaddset(&act.sa_mask, SIGQUIT);
72         act.sa_flags = SA_RESETHAND;
73         return sigaction(SIGSEGV, &act, nullptr);
74     }
75 };
76 
ForkBySyscall(void)77 static pid_t ForkBySyscall(void)
78 {
79 #ifdef SYS_fork
80     return syscall(SYS_fork);
81 #else
82     return syscall(SYS_clone, SIGCHLD, 0);
83 #endif
84 }
85 
HWTEST_F_L0(ReadOnlySpaceTest,ReadOnlyTest)86 HWTEST_F_L0(ReadOnlySpaceTest, ReadOnlyTest)
87 {
88     auto *heap = const_cast<panda::ecmascript::Heap *>(thread->GetEcmaVM()->GetHeap());
89     if (!g_isEnableCMCGC) {
90         heap->GetReadOnlySpace()->SetReadOnly();
91     } else {
92         auto heapManager = common::BaseRuntime::GetInstance()->GetHeapManager();
93         heapManager.SetReadOnlyToROSpace();
94     }
95     if (ReadOnlyTestManager::RegisterSignal() == -1) {
96         perror("sigaction error");
97         exit(1);
98     }
99     if (!g_isEnableCMCGC) {
100         SharedHeap::GetInstance()->WaitGCFinished(thread);
101     }
102     auto ret = sigsetjmp(g_env, 1);
103     if (ret != SIGSEGV) {
104         heap->AllocateReadOnlyOrHugeObject(
105             JSHClass::Cast(thread->GlobalConstants()->GetBigIntClass().GetTaggedObject()));
106     } else {
107         // catch signal SIGSEGV caused by modify read only memory
108         EXPECT_TRUE(g_segmentfault_flag);
109     }
110     if (g_isEnableCMCGC) {
111         EXPECT_TRUE(g_segmentfault_flag);
112     }
113 }
114 
HWTEST_F_L0(ReadOnlySpaceTest,AllocateTest)115 HWTEST_F_L0(ReadOnlySpaceTest, AllocateTest)
116 {
117     auto *heap = const_cast<panda::ecmascript::Heap *>(thread->GetEcmaVM()->GetHeap());
118     auto *object = heap->AllocateReadOnlyOrHugeObject(
119         JSHClass::Cast(thread->GlobalConstants()->GetBigIntClass().GetTaggedObject()));
120     if (!g_isEnableCMCGC) {
121         auto *region = Region::ObjectAddressToRange(object);
122         EXPECT_TRUE(region->InReadOnlySpace());
123     } else {
124         auto heapManager = common::BaseRuntime::GetInstance()->GetHeapManager();
125         EXPECT_TRUE(heapManager.IsInROSpace(object));
126     }
127 }
128 
HWTEST_F_L0(ReadOnlySpaceTest,CompactHeapBeforeForkTest)129 HWTEST_F_L0(ReadOnlySpaceTest, CompactHeapBeforeForkTest)
130 {
131     if (!g_isEnableCMCGC) {
132         auto *heap = const_cast<panda::ecmascript::Heap *>(thread->GetEcmaVM()->GetHeap());
133         std::string rawStr = "test string";
134         JSHandle<EcmaString> string = factory->NewFromStdString(rawStr);
135         JSHandle<JSObject> obj = factory->NewEmptyJSObject();
136         auto *regionBefore = Region::ObjectAddressToRange(string.GetObject<TaggedObject>());
137         auto *objRegionBefore = Region::ObjectAddressToRange(obj.GetObject<TaggedObject>());
138         EXPECT_TRUE(regionBefore->InSharedHeap());
139         EXPECT_FALSE(objRegionBefore->InReadOnlySpace());
140         heap->CompactHeapBeforeFork();
141         auto *regionAfter = Region::ObjectAddressToRange(string.GetObject<TaggedObject>());
142         auto *objRegionAfter = Region::ObjectAddressToRange(obj.GetObject<TaggedObject>());
143         EXPECT_TRUE(regionAfter->InSharedHeap());
144         EXPECT_FALSE(objRegionAfter->InReadOnlySpace());
145     } else {
146         EXPECT_TRUE(true);
147     }
148 }
149 
HWTEST_F_L0(ReadOnlySpaceTest,GCTest)150 HWTEST_F_L0(ReadOnlySpaceTest, GCTest)
151 {
152     auto *heap = const_cast<panda::ecmascript::Heap *>(thread->GetEcmaVM()->GetHeap());
153     auto *object = heap->AllocateReadOnlyOrHugeObject(
154         JSHClass::Cast(thread->GlobalConstants()->GetBigIntClass().GetTaggedObject()));
155     if (!g_isEnableCMCGC) {
156         heap->CollectGarbage(TriggerGCType::YOUNG_GC);
157         heap->CollectGarbage(TriggerGCType::OLD_GC);
158         heap->CollectGarbage(TriggerGCType::FULL_GC);
159         auto *region = Region::ObjectAddressToRange(object);
160         EXPECT_TRUE(region->InReadOnlySpace());
161     } else {
162         auto baseRuntime = common::BaseRuntime::GetInstance();
163         auto heapManager = baseRuntime->GetHeapManager();
164         baseRuntime->RequestGC(common::GC_REASON_BACKUP, false, common::GC_TYPE_FULL);
165         EXPECT_TRUE(heapManager.IsInROSpace(object));
166     }
167 }
168 
HWTEST_F_L0(ReadOnlySpaceTest,ForkTest)169 HWTEST_F_L0(ReadOnlySpaceTest, ForkTest)
170 {
171     auto vm = thread->GetEcmaVM();
172     auto *heap = const_cast<panda::ecmascript::Heap *>(thread->GetEcmaVM()->GetHeap());
173     if (!g_isEnableCMCGC) {
174         std::string rawStr = "fork string";
175         JSHandle<EcmaString> string = factory->NewFromStdString(rawStr);
176         JSNApi::PreFork(vm);
177         if (ForkBySyscall() == 0) {
178             panda::RuntimeOption postOption;
179             JSNApi::PostFork(vm, postOption);
180             // test gc in child process
181             heap->CollectGarbage(TriggerGCType::OLD_GC);
182             auto *region = Region::ObjectAddressToRange(string.GetObject<TaggedObject>());
183             EXPECT_TRUE(region->InSharedHeap());
184         }
185     } else {
186         auto *object = heap->AllocateReadOnlyOrHugeObject(
187                 JSHClass::Cast(thread->GlobalConstants()->GetBigIntClass().GetTaggedObject()));
188         auto baseRuntime = common::BaseRuntime::GetInstance();
189         auto heapManager = baseRuntime->GetHeapManager();
190 
191         JSNApi::PreFork(vm);
192         if (ForkBySyscall() == 0) {
193             panda::RuntimeOption postOption;
194             JSNApi::PostFork(vm, postOption);
195             // test gc in child process
196             baseRuntime->RequestGC(common::GC_REASON_BACKUP, false, common::GC_TYPE_FULL);
197             EXPECT_TRUE(heapManager.IsInROSpace(object));
198         } else {
199             int status;
200             pid_t ter_pid = wait(&status);
201             if (ter_pid == -1)
202             {
203                 exit(1);
204             }
205         }
206     }
207 }
208 }  // namespace panda::test
209