• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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