• 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.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