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