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> 31using namespace panda::ecmascript; 32 33namespace panda::test { 34class ReadOnlySpaceTest : public BaseTestWithScope<false> { 35public: 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 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 54static sigjmp_buf g_env; 55static bool g_segmentfault_flag = false; 56class ReadOnlyTestManager { 57public: 58 // static constexpr int RO_SEGMENTFAULT = 1; 59 static void ProcessReadOnlySegmentFault(int sig) 60 { 61 g_segmentfault_flag = true; 62 siglongjmp(g_env, sig); 63 } 64 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 76static 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 85HWTEST_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 104HWTEST_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 113HWTEST_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 130HWTEST_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 142HWTEST_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 // test gc in parent process 151 heap->CollectGarbage(TriggerGCType::OLD_GC); 152 } else { 153 panda::RuntimeOption postOption; 154 JSNApi::PostFork(vm, postOption); 155 // test gc in child process 156 heap->CollectGarbage(TriggerGCType::OLD_GC); 157 auto *region = Region::ObjectAddressToRange(string.GetObject<TaggedObject>()); 158 EXPECT_TRUE(region->InSharedHeap()); 159 } 160} 161} // namespace panda::test 162