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.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
28 #include <csetjmp>
29 #include <csignal>
30 #include <sys/syscall.h>
31 using namespace panda::ecmascript;
32
33 namespace panda::test {
34 class ReadOnlySpaceTest : public BaseTestWithScope<false> {
35 public:
SetUp()36 void SetUp() override
37 {
38 InitializeLogger();
39 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
40 factory = thread->GetEcmaVM()->GetFactory();
41 const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->SetMarkType(MarkType::MARK_FULL);
42 }
43
InitializeLogger()44 void InitializeLogger()
45 {
46 panda::ecmascript::JSRuntimeOptions runtimeOptions;
47 runtimeOptions.SetLogLevel("error");
48 ecmascript::Log::Initialize(runtimeOptions);
49 }
50
51 ObjectFactory *factory {nullptr};
52 };
53
54 static sigjmp_buf g_env;
55 static bool g_segmentfault_flag = false;
56 class ReadOnlyTestManager {
57 public:
58 // static constexpr int RO_SEGMENTFAULT = 1;
ProcessReadOnlySegmentFault(int sig)59 static void ProcessReadOnlySegmentFault(int sig)
60 {
61 g_segmentfault_flag = true;
62 siglongjmp(g_env, sig);
63 }
64
RegisterSignal()65 static int RegisterSignal()
66 {
67 struct sigaction act;
68 act.sa_handler = ProcessReadOnlySegmentFault;
69 sigemptyset(&act.sa_mask);
70 sigaddset(&act.sa_mask, SIGQUIT);
71 act.sa_flags = SA_RESETHAND;
72 return sigaction(SIGSEGV, &act, nullptr);
73 }
74 };
75
ForkBySyscall(void)76 static pid_t ForkBySyscall(void)
77 {
78 #ifdef SYS_fork
79 return syscall(SYS_fork);
80 #else
81 return syscall(SYS_clone, SIGCHLD, 0);
82 #endif
83 }
84
HWTEST_F_L0(ReadOnlySpaceTest,ReadOnlyTest)85 HWTEST_F_L0(ReadOnlySpaceTest, ReadOnlyTest)
86 {
87 auto *heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
88 heap->GetReadOnlySpace()->SetReadOnly();
89 if (ReadOnlyTestManager::RegisterSignal() == -1) {
90 perror("sigaction error");
91 exit(1);
92 }
93 SharedHeap::GetInstance()->WaitGCFinished(thread);
94 auto ret = sigsetjmp(g_env, 1);
95 if (ret != SIGSEGV) {
96 heap->AllocateReadOnlyOrHugeObject(
97 JSHClass::Cast(thread->GlobalConstants()->GetBigIntClass().GetTaggedObject()));
98 } else {
99 // catch signal SIGSEGV caused by modify read only memory
100 EXPECT_TRUE(g_segmentfault_flag);
101 }
102 }
103
HWTEST_F_L0(ReadOnlySpaceTest,AllocateTest)104 HWTEST_F_L0(ReadOnlySpaceTest, AllocateTest)
105 {
106 auto *heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
107 auto *object = heap->AllocateReadOnlyOrHugeObject(
108 JSHClass::Cast(thread->GlobalConstants()->GetBigIntClass().GetTaggedObject()));
109 auto *region = Region::ObjectAddressToRange(object);
110 EXPECT_TRUE(region->InReadOnlySpace());
111 }
112
HWTEST_F_L0(ReadOnlySpaceTest,CompactHeapBeforeForkTest)113 HWTEST_F_L0(ReadOnlySpaceTest, CompactHeapBeforeForkTest)
114 {
115 auto *heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
116 std::string rawStr = "test string";
117 JSHandle<EcmaString> string = factory->NewFromStdString(rawStr);
118 JSHandle<JSObject> obj = factory->NewEmptyJSObject();
119 auto *regionBefore = Region::ObjectAddressToRange(string.GetObject<TaggedObject>());
120 auto *objRegionBefore = Region::ObjectAddressToRange(obj.GetObject<TaggedObject>());
121 EXPECT_TRUE(regionBefore->InSharedHeap());
122 EXPECT_FALSE(objRegionBefore->InReadOnlySpace());
123 heap->CompactHeapBeforeFork();
124 auto *regionAfter = Region::ObjectAddressToRange(string.GetObject<TaggedObject>());
125 auto *objRegionAfter = Region::ObjectAddressToRange(obj.GetObject<TaggedObject>());
126 EXPECT_TRUE(regionAfter->InSharedHeap());
127 EXPECT_FALSE(objRegionAfter->InReadOnlySpace());
128 }
129
HWTEST_F_L0(ReadOnlySpaceTest,GCTest)130 HWTEST_F_L0(ReadOnlySpaceTest, GCTest)
131 {
132 auto *heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
133 auto *object = heap->AllocateReadOnlyOrHugeObject(
134 JSHClass::Cast(thread->GlobalConstants()->GetBigIntClass().GetTaggedObject()));
135 heap->CollectGarbage(TriggerGCType::YOUNG_GC);
136 heap->CollectGarbage(TriggerGCType::OLD_GC);
137 heap->CollectGarbage(TriggerGCType::FULL_GC);
138 auto *region = Region::ObjectAddressToRange(object);
139 EXPECT_TRUE(region->InReadOnlySpace());
140 }
141
HWTEST_F_L0(ReadOnlySpaceTest,ForkTest)142 HWTEST_F_L0(ReadOnlySpaceTest, ForkTest)
143 {
144 auto vm = thread->GetEcmaVM();
145 auto *heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
146 std::string rawStr = "fork string";
147 JSHandle<EcmaString> string = factory->NewFromStdString(rawStr);
148 JSNApi::PreFork(vm);
149 if (ForkBySyscall() == 0) {
150 panda::RuntimeOption postOption;
151 JSNApi::PostFork(vm, postOption);
152 // test gc in child process
153 heap->CollectGarbage(TriggerGCType::OLD_GC);
154 auto *region = Region::ObjectAddressToRange(string.GetObject<TaggedObject>());
155 EXPECT_TRUE(region->InSharedHeap());
156 }
157 }
158 } // namespace panda::test
159