1/* 2 * Copyright (c) 2024 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 <gtest/gtest.h> 17#include <csignal> 18#include <map> 19#include <securec.h> 20#include <string> 21#include <thread> 22#include <unistd.h> 23#include <vector> 24#include <sys/prctl.h> 25 26#include "dfx_define.h" 27#include "dfx_signal_local_handler.h" 28#include "dfx_socket_request.h" 29#include "dfx_test_util.h" 30#include "dfx_allocator.h" 31#include "faultloggerd_client.h" 32 33#define MALLOC_TEST_TIMES 1000 34#define MALLOC_TEST_SMALL_SIZE 16 35#define MALLOC_TEST_BIG_SIZE 2000 36 37using namespace testing; 38using namespace testing::ext; 39using namespace std; 40 41namespace OHOS { 42namespace HiviewDFX { 43class LocalHandlerTest : public testing::Test { 44public: 45 static void SetUpTestCase(); 46 static void TearDownTestCase(); 47 void SetUp(); 48 void TearDown(); 49}; 50 51void LocalHandlerTest::SetUpTestCase() 52{} 53 54void LocalHandlerTest::TearDownTestCase() 55{} 56 57void LocalHandlerTest::SetUp() 58{} 59 60void LocalHandlerTest::TearDown() 61{} 62 63static bool CheckLocalCrashKeyWords(const string& filePath, pid_t pid, int sig) 64{ 65 if (filePath.empty() || pid <= 0) { 66 return false; 67 } 68 map<int, string> sigKey = { 69 { SIGILL, string("Signal(4)") }, 70 { SIGABRT, string("Signal(6)") }, 71 { SIGBUS, string("Signal(7)") }, 72 { SIGSEGV, string("Signal(11)") }, 73 }; 74 string sigKeyword = ""; 75 map<int, string>::iterator iter = sigKey.find(sig); 76 if (iter != sigKey.end()) { 77 sigKeyword = iter->second; 78 } 79#ifdef __aarch64__ 80 string keywords[] = { 81 "Pid:" + to_string(pid), "Uid:", "name:./test_localhandler", 82 sigKeyword, "Tid:", "#00", "x0:", "test_localhandler" 83 }; 84#else 85 string keywords[] = { 86 "Pid:" + to_string(pid), "Uid:", "name:./test_localhandler", 87 sigKeyword, "Tid:", "#00", "test_localhandler" 88 }; 89#endif 90 91 int length = sizeof(keywords) / sizeof(keywords[0]); 92 int minRegIdx = -1; 93 return CheckKeyWords(filePath, keywords, length, minRegIdx) == length; 94} 95 96/** 97 * @tc.name: LocalHandlerTest001 98 * @tc.desc: test crashlocalhandler signo(SIGILL) 99 * @tc.type: FUNC 100 */ 101HWTEST_F(LocalHandlerTest, LocalHandlerTest001, TestSize.Level2) 102{ 103 GTEST_LOG_(INFO) << "LocalHandlerTest001: start."; 104 pid_t pid = fork(); 105 if (pid < 0) { 106 GTEST_LOG_(ERROR) << "Failed to fork new test process."; 107 } else if (pid == 0) { 108 DFX_InstallLocalSignalHandler(); 109 sleep(1); 110 } else { 111 usleep(10000); // 10000 : sleep 10ms 112 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")"; 113 kill(pid, SIGILL); 114 sleep(2); // 2 : wait for cppcrash generating 115 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGILL); 116 ASSERT_TRUE(ret); 117 } 118 GTEST_LOG_(INFO) << "LocalHandlerTest001: end."; 119} 120 121/** 122 * @tc.name: LocalHandlerTest002 123 * @tc.desc: test crashlocalhandler signo(SIGABRT) 124 * @tc.type: FUNC 125 */ 126HWTEST_F(LocalHandlerTest, LocalHandlerTest002, TestSize.Level2) 127{ 128 GTEST_LOG_(INFO) << "LocalHandlerTest002: start."; 129 pid_t pid = fork(); 130 if (pid < 0) { 131 GTEST_LOG_(ERROR) << "Failed to fork new test process."; 132 } else if (pid == 0) { 133 DFX_InstallLocalSignalHandler(); 134 sleep(1); 135 } else { 136 usleep(10000); // 10000 : sleep 10ms 137 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")"; 138 kill(pid, SIGABRT); 139 sleep(2); // 2 : wait for cppcrash generating 140 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGABRT); 141 ASSERT_TRUE(ret); 142 } 143 GTEST_LOG_(INFO) << "LocalHandlerTest002: end."; 144} 145 146/** 147 * @tc.name: LocalHandlerTest003 148 * @tc.desc: test crashlocalhandler signo(SIGBUS) 149 * @tc.type: FUNC 150 */ 151HWTEST_F(LocalHandlerTest, LocalHandlerTest003, TestSize.Level2) 152{ 153 GTEST_LOG_(INFO) << "LocalHandlerTest003: start."; 154 pid_t pid = fork(); 155 if (pid < 0) { 156 GTEST_LOG_(ERROR) << "Failed to fork new test process."; 157 } else if (pid == 0) { 158 DFX_InstallLocalSignalHandler(); 159 sleep(1); 160 } else { 161 usleep(10000); // 10000 : sleep 10ms 162 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")"; 163 kill(pid, SIGBUS); 164 sleep(2); // 2 : wait for cppcrash generating 165 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGBUS); 166 ASSERT_TRUE(ret); 167 } 168 GTEST_LOG_(INFO) << "LocalHandlerTest003: end."; 169} 170 171/** 172 * @tc.name: LocalHandlerTest004 173 * @tc.desc: test crashlocalhandler signo(SIGSEGV) 174 * @tc.type: FUNC 175 */ 176HWTEST_F(LocalHandlerTest, LocalHandlerTest004, TestSize.Level2) 177{ 178 GTEST_LOG_(INFO) << "LocalHandlerTest004: start."; 179 pid_t pid = fork(); 180 if (pid < 0) { 181 GTEST_LOG_(ERROR) << "Failed to fork new test process."; 182 } else if (pid == 0) { 183 DFX_InstallLocalSignalHandler(); 184 sleep(1); 185 } else { 186 usleep(10000); // 10000 : sleep 10ms 187 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")"; 188 kill(pid, SIGSEGV); 189 sleep(2); // 2 : wait for cppcrash generating 190 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV); 191 ASSERT_TRUE(ret); 192 } 193 GTEST_LOG_(INFO) << "LocalHandlerTest004: end."; 194} 195 196/** 197 * @tc.name: LocalHandlerTest005 198 * @tc.desc: test crashlocalhandler signo(SIGSEGV) by execl 199 * @tc.type: FUNC 200 */ 201HWTEST_F(LocalHandlerTest, LocalHandlerTest005, TestSize.Level2) 202{ 203 GTEST_LOG_(INFO) << "LocalHandlerTest005: start."; 204 pid_t pid = fork(); 205 if (pid < 0) { 206 GTEST_LOG_(ERROR) << "Failed to fork new test process."; 207 } else if (pid == 0) { 208 DFX_InstallLocalSignalHandler(); 209 sleep(1); 210 raise(SIGSEGV); 211 } else { 212 usleep(10000); // 10000 : sleep 10ms 213 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")"; 214 sleep(2); // 2 : wait for cppcrash generating 215 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV); 216 ASSERT_TRUE(ret); 217 } 218 GTEST_LOG_(INFO) << "LocalHandlerTest005: end."; 219} 220 221/** 222 * @tc.name: LocalHandlerTest006 223 * @tc.desc: test crashlocalhandler signo(SIGSEGV) by execl 224 * @tc.type: FUNC 225 */ 226HWTEST_F(LocalHandlerTest, LocalHandlerTest006, TestSize.Level2) 227{ 228 GTEST_LOG_(INFO) << "LocalHandlerTest006: start."; 229 pid_t pid = fork(); 230 if (pid < 0) { 231 GTEST_LOG_(ERROR) << "Failed to fork new test process."; 232 } else if (pid == 0) { 233 siginfo_t siginfo { 234 .si_signo = SIGSEGV 235 }; 236 DFX_SignalLocalHandler(SIGSEGV, &siginfo, nullptr); 237 } else { 238 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")"; 239 sleep(2); // 2 : wait for cppcrash generating 240 ASSERT_TRUE(CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV)); 241 } 242 GTEST_LOG_(INFO) << "LocalHandlerTest006: end."; 243} 244 245/** 246 * @tc.name: LocalHandlerTest007 247 * @tc.desc: test crashlocalhandler signo(SIGSEGV) by execl 248 * @tc.type: FUNC 249 */ 250HWTEST_F(LocalHandlerTest, LocalHandlerTest007, TestSize.Level2) 251{ 252 GTEST_LOG_(INFO) << "LocalHandlerTest005: start."; 253 pid_t pid = fork(); 254 if (pid < 0) { 255 GTEST_LOG_(ERROR) << "Failed to fork new test process."; 256 } else if (pid == 0) { 257 siginfo_t siginfo { 258 .si_signo = SIGSEGV 259 }; 260 DFX_GetCrashFdFunc([]{return RequestFileDescriptor((int)FaultLoggerType::CPP_CRASH);}); 261 DFX_SignalLocalHandler(SIGSEGV, &siginfo, nullptr); 262 } else { 263 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")"; 264 sleep(2); // 2 : wait for cppcrash generating 265 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV); 266 ASSERT_TRUE(ret); 267 } 268 GTEST_LOG_(INFO) << "LocalHandlerTest007: end."; 269} 270 271/** 272 * @tc.name: DfxAllocatorTest001 273 * @tc.desc: test dfxAllocator isDfxAllocatorMem 274 * @tc.type: FUNC 275 */ 276HWTEST_F(LocalHandlerTest, DfxAllocatorTest001, TestSize.Level2) 277{ 278 GTEST_LOG_(INFO) << "DfxAllocatorTest001: start."; 279 void* p = malloc(MALLOC_TEST_SMALL_SIZE); 280 int ret = 0; 281 if (p) { 282 ret = IsDfxAllocatorMem(p); 283 free(p); 284 } 285 ASSERT_TRUE(ret == 0); 286 GTEST_LOG_(INFO) << "DfxAllocatorTest001: end."; 287} 288 289/** 290 * @tc.name: DfxAllocatorTest002 291 * @tc.desc: test dfxAllocator malloc and free 292 * @tc.type: FUNC 293 */ 294HWTEST_F(LocalHandlerTest, DfxAllocatorTest002, TestSize.Level2) 295{ 296 GTEST_LOG_(INFO) << "DfxAllocatorTest002: start."; 297 void* p = nullptr; 298 void* parr[MALLOC_TEST_TIMES] = {nullptr}; 299 uint32_t size = MALLOC_TEST_SMALL_SIZE; 300 int res = 0; 301 DfxAllocator* allocator = GetDfxAllocator(); 302 RegisterAllocator(); 303 for (int i = 0; i < DFX_MEMPOOLS_NUM; i++) { 304 // malloc and free 1000 times 305 for (int time = 0; time < MALLOC_TEST_TIMES; time++) { 306 p = malloc(size); 307 if (p == nullptr || !IsDfxAllocatorMem(p)) { 308 res = 1; 309 } 310 free(p); 311 if (allocator->dfxMempoolBuf[i].pageList != nullptr) { 312 res = 1; 313 } 314 } 315 // malloc 1000 times and free 1000 times 316 for (int time = 0; time < MALLOC_TEST_TIMES; time++) { 317 parr[time] = malloc(size); 318 if (parr[time] == nullptr || !IsDfxAllocatorMem(parr[time])) { 319 res = 1; 320 } 321 } 322 for (int time = 0; time < MALLOC_TEST_TIMES; time++) { 323 free(parr[time]); 324 } 325 if (allocator->dfxMempoolBuf[i].pageList != nullptr) { 326 res = 1; 327 } 328 size = size << 1; 329 } 330 UnregisterAllocator(); 331 ASSERT_TRUE(res == 0); 332 GTEST_LOG_(INFO) << "DfxAllocatorTest002: end."; 333} 334 335/** 336 * @tc.name: DfxAllocatorTest003 337 * @tc.desc: test dfxAllocator mmap 338 * @tc.type: FUNC 339 */ 340HWTEST_F(LocalHandlerTest, DfxAllocatorTest003, TestSize.Level2) 341{ 342 GTEST_LOG_(INFO) << "DfxAllocatorTest003: start."; 343 void* p = nullptr; 344 void* parr[MALLOC_TEST_TIMES] = {nullptr}; 345 uint32_t size = MALLOC_TEST_BIG_SIZE; 346 int res = 0; 347 DfxAllocator* allocator = GetDfxAllocator(); 348 RegisterAllocator(); 349 // malloc and free 1000 times 350 for (int time = 0; time < MALLOC_TEST_TIMES; time++) { 351 p = malloc(size); 352 if (p == nullptr || !IsDfxAllocatorMem(p)) { 353 res = 1; 354 } 355 free(p); 356 if (allocator->pageList != nullptr) { 357 res = 1; 358 } 359 } 360 // malloc 1000 times and free 1000 times 361 for (int time = 0; time < MALLOC_TEST_TIMES; time++) { 362 parr[time] = malloc(size); 363 if (parr[time] == nullptr || !IsDfxAllocatorMem(parr[time])) { 364 res = 1; 365 } 366 } 367 for (int time = 0; time < MALLOC_TEST_TIMES; time++) { 368 free(parr[time]); 369 } 370 if (allocator->pageList != nullptr) { 371 res = 1; 372 } 373 UnregisterAllocator(); 374 ASSERT_TRUE(res == 0); 375 GTEST_LOG_(INFO) << "DfxAllocatorTest003: end."; 376} 377 378/** 379 * @tc.name: DfxAllocatorTest004 380 * @tc.desc: test dfxAllocator realloc 381 * @tc.type: FUNC 382 */ 383HWTEST_F(LocalHandlerTest, DfxAllocatorTest004, TestSize.Level2) 384{ 385 GTEST_LOG_(INFO) << "DfxAllocatorTest004: start."; 386 void* p = nullptr; 387 uint32_t size = MALLOC_TEST_SMALL_SIZE; 388 int res = 0; 389 DfxAllocator* allocator = GetDfxAllocator(); 390 RegisterAllocator(); 391 p = malloc(size); 392 (void)memset_s(p, size, 0, size); 393 size += MALLOC_TEST_SMALL_SIZE; 394 p = realloc(p, size); 395 if (p == nullptr || !IsDfxAllocatorMem(p)) { 396 res = 1; 397 } 398 if (allocator->dfxMempoolBuf[1].pageList == nullptr) { 399 res = 1; 400 } 401 free(p); 402 UnregisterAllocator(); 403 ASSERT_TRUE(res == 0); 404 GTEST_LOG_(INFO) << "DfxAllocatorTest004: end."; 405} 406 407/** 408 * @tc.name: DfxAllocatorTest005 409 * @tc.desc: test dfxAllocator localhandler crash log 410 * @tc.type: FUNC 411 */ 412HWTEST_F(LocalHandlerTest, DfxAllocatorTest005, TestSize.Level2) 413{ 414 GTEST_LOG_(INFO) << "DfxAllocatorTest005: start."; 415 pid_t pid = fork(); 416 if (pid < 0) { 417 GTEST_LOG_(ERROR) << "Failed to fork new test process."; 418 } else if (pid == 0) { 419 DFX_InstallLocalSignalHandler(); 420 sleep(1); 421 // alloc a buffer 422 int32_t initAllocSz = 10; 423 int32_t reallocSz = 20; 424 int8_t* addr = reinterpret_cast<int8_t*>(malloc(initAllocSz)); 425 // overwrite the control block 426 int8_t* newAddr = addr - initAllocSz; 427 (void)memset_s(newAddr, initAllocSz, 0, initAllocSz); 428 addr = reinterpret_cast<int8_t*>(realloc(reinterpret_cast<void*>(addr), reallocSz)); 429 free(addr); 430 // force crash if not crash in realloc 431 abort(); 432 } else { 433 usleep(10000); // 10000 : sleep 10ms 434 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")"; 435 sleep(2); // 2 : wait for cppcrash generating 436#ifdef __aarch64__ 437 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGABRT); 438#else 439 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV); 440#endif 441 ASSERT_TRUE(ret); 442 } 443 GTEST_LOG_(INFO) << "DfxAllocatorTest005: end."; 444} 445 446/** 447 * @tc.name: DfxAllocatorTest006 448 * @tc.desc: test dfxAllocator localhandler abnormal scenario 449 * @tc.type: FUNC 450 */ 451HWTEST_F(LocalHandlerTest, DfxAllocatorTest006, TestSize.Level2) 452{ 453 GTEST_LOG_(INFO) << "DfxAllocatorTest005: start."; 454 int ret = IsDfxAllocatorMem(nullptr); 455 ASSERT_EQ(ret, 0); 456 GTEST_LOG_(INFO) << "DfxAllocatorTest005: end."; 457} 458} // namespace HiviewDFX 459} // namepsace OHOS 460