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 
37 using namespace testing;
38 using namespace testing::ext;
39 using namespace std;
40 
41 namespace OHOS {
42 namespace HiviewDFX {
43 class LocalHandlerTest : public testing::Test {
44 public:
45     static void SetUpTestCase();
46     static void TearDownTestCase();
47     void SetUp();
48     void TearDown();
49 };
50 
SetUpTestCase()51 void LocalHandlerTest::SetUpTestCase()
52 {}
53 
TearDownTestCase()54 void LocalHandlerTest::TearDownTestCase()
55 {}
56 
SetUp()57 void LocalHandlerTest::SetUp()
58 {}
59 
TearDown()60 void LocalHandlerTest::TearDown()
61 {}
62 
CheckLocalCrashKeyWords(const string & filePath,pid_t pid,int sig)63 static 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("SIGILL") },
70         { SIGABRT, string("SIGABRT") },
71         { SIGBUS, string("SIGBUS") },
72         { SIGSEGV, string("SIGSEGV") },
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  */
101 HWTEST_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  */
126 HWTEST_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  */
151 HWTEST_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  */
176 HWTEST_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  */
201 HWTEST_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  */
226 HWTEST_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  */
250 HWTEST_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([](const struct ProcessDumpRequest* request)
__anon4355cd240102(const struct ProcessDumpRequest* request) 261             {return RequestFileDescriptor((int)FaultLoggerType::CPP_CRASH);});
262         DFX_SignalLocalHandler(SIGSEGV, &siginfo, nullptr);
263     } else {
264         GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")";
265         sleep(2); // 2 : wait for cppcrash generating
266         bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
267         ASSERT_TRUE(ret);
268     }
269     GTEST_LOG_(INFO) << "LocalHandlerTest007: end.";
270 }
271 
272 /**
273  * @tc.name: DfxAllocatorTest001
274  * @tc.desc: test dfxAllocator isDfxAllocatorMem
275  * @tc.type: FUNC
276  */
277 HWTEST_F(LocalHandlerTest, DfxAllocatorTest001, TestSize.Level2)
278 {
279     GTEST_LOG_(INFO) << "DfxAllocatorTest001: start.";
280     void* p = malloc(MALLOC_TEST_SMALL_SIZE);
281     int ret = 0;
282     if (p) {
283         ret = IsDfxAllocatorMem(p);
284         free(p);
285     }
286     ASSERT_TRUE(ret == 0);
287     GTEST_LOG_(INFO) << "DfxAllocatorTest001: end.";
288 }
289 
290 /**
291  * @tc.name: DfxAllocatorTest002
292  * @tc.desc: test dfxAllocator malloc and free
293  * @tc.type: FUNC
294  */
295 HWTEST_F(LocalHandlerTest, DfxAllocatorTest002, TestSize.Level2)
296 {
297     GTEST_LOG_(INFO) << "DfxAllocatorTest002: start.";
298     void* p = nullptr;
299     void* parr[MALLOC_TEST_TIMES] = {nullptr};
300     uint32_t size = MALLOC_TEST_SMALL_SIZE;
301     int res = 0;
302     DfxAllocator* allocator = GetDfxAllocator();
303     RegisterAllocator();
304     for (int i = 0; i < DFX_MEMPOOLS_NUM; i++) {
305         // malloc and free 1000 times
306         for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
307             p = malloc(size);
308             if (p == nullptr || !IsDfxAllocatorMem(p)) {
309                 res = 1;
310             }
311             free(p);
312             if (allocator->dfxMempoolBuf[i].pageList != nullptr) {
313                 res = 1;
314             }
315         }
316         // malloc 1000 times and free 1000 times
317         for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
318             parr[time] = malloc(size);
319             if (parr[time] == nullptr || !IsDfxAllocatorMem(parr[time])) {
320                 res = 1;
321             }
322         }
323         for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
324             free(parr[time]);
325         }
326         if (allocator->dfxMempoolBuf[i].pageList != nullptr) {
327             res = 1;
328         }
329         size = size << 1;
330     }
331     UnregisterAllocator();
332     ASSERT_TRUE(res == 0);
333     GTEST_LOG_(INFO) << "DfxAllocatorTest002: end.";
334 }
335 
336 /**
337  * @tc.name: DfxAllocatorTest003
338  * @tc.desc: test dfxAllocator mmap
339  * @tc.type: FUNC
340  */
341 HWTEST_F(LocalHandlerTest, DfxAllocatorTest003, TestSize.Level2)
342 {
343     GTEST_LOG_(INFO) << "DfxAllocatorTest003: start.";
344     void* p = nullptr;
345     void* parr[MALLOC_TEST_TIMES] = {nullptr};
346     uint32_t size = MALLOC_TEST_BIG_SIZE;
347     int res = 0;
348     DfxAllocator* allocator = GetDfxAllocator();
349     RegisterAllocator();
350     // malloc and free 1000 times
351     for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
352         p = malloc(size);
353         if (p == nullptr || !IsDfxAllocatorMem(p)) {
354             res = 1;
355         }
356         free(p);
357         if (allocator->pageList != nullptr) {
358             res = 1;
359         }
360     }
361     // malloc 1000 times and free 1000 times
362     for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
363         parr[time] = malloc(size);
364         if (parr[time] == nullptr || !IsDfxAllocatorMem(parr[time])) {
365             res = 1;
366         }
367     }
368     for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
369         free(parr[time]);
370     }
371     if (allocator->pageList != nullptr) {
372         res = 1;
373     }
374     UnregisterAllocator();
375     ASSERT_TRUE(res == 0);
376     GTEST_LOG_(INFO) << "DfxAllocatorTest003: end.";
377 }
378 
379 /**
380  * @tc.name: DfxAllocatorTest004
381  * @tc.desc: test dfxAllocator realloc
382  * @tc.type: FUNC
383  */
384 HWTEST_F(LocalHandlerTest, DfxAllocatorTest004, TestSize.Level2)
385 {
386     GTEST_LOG_(INFO) << "DfxAllocatorTest004: start.";
387     void* p = nullptr;
388     uint32_t size = MALLOC_TEST_SMALL_SIZE;
389     int res = 0;
390     DfxAllocator* allocator = GetDfxAllocator();
391     RegisterAllocator();
392     p = malloc(size);
393     (void)memset_s(p, size, 0, size);
394     size += MALLOC_TEST_SMALL_SIZE;
395     p = realloc(p, size);
396     if (p == nullptr || !IsDfxAllocatorMem(p)) {
397         res = 1;
398     }
399     if (allocator->dfxMempoolBuf[1].pageList == nullptr) {
400         res = 1;
401     }
402     free(p);
403     UnregisterAllocator();
404     ASSERT_TRUE(res == 0);
405     GTEST_LOG_(INFO) << "DfxAllocatorTest004: end.";
406 }
407 
408 /**
409  * @tc.name: DfxAllocatorTest005
410  * @tc.desc: test dfxAllocator localhandler crash log
411  * @tc.type: FUNC
412  */
413 HWTEST_F(LocalHandlerTest, DfxAllocatorTest005, TestSize.Level2)
414 {
415     GTEST_LOG_(INFO) << "DfxAllocatorTest005: start.";
416     pid_t pid = fork();
417     if (pid < 0) {
418         GTEST_LOG_(ERROR) << "Failed to fork new test process.";
419     } else if (pid == 0) {
420         DFX_InstallLocalSignalHandler();
421         sleep(1);
422         // alloc a buffer
423         int32_t initAllocSz = 10;
424         int32_t reallocSz = 20;
425         int8_t* addr = reinterpret_cast<int8_t*>(malloc(initAllocSz));
426         // overwrite the control block
427         int8_t* newAddr = addr - initAllocSz;
428         (void)memset_s(newAddr, initAllocSz, 0, initAllocSz);
429         addr = reinterpret_cast<int8_t*>(realloc(reinterpret_cast<void*>(addr), reallocSz));
430         free(addr);
431         // force crash if not crash in realloc
432         abort();
433     } else {
434         usleep(10000); // 10000 : sleep 10ms
435         GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")";
436         sleep(2); // 2 : wait for cppcrash generating
437 #ifdef __aarch64__
438         bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGABRT);
439 #else
440         bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
441 #endif
442         ASSERT_TRUE(ret);
443     }
444     GTEST_LOG_(INFO) << "DfxAllocatorTest005: end.";
445 }
446 
447 /**
448  * @tc.name: DfxAllocatorTest006
449  * @tc.desc: test dfxAllocator localhandler abnormal scenario
450  * @tc.type: FUNC
451  */
452 HWTEST_F(LocalHandlerTest, DfxAllocatorTest006, TestSize.Level2)
453 {
454     GTEST_LOG_(INFO) << "DfxAllocatorTest005: start.";
455     int ret = IsDfxAllocatorMem(nullptr);
456     ASSERT_EQ(ret, 0);
457     GTEST_LOG_(INFO) << "DfxAllocatorTest005: end.";
458 }
459 } // namespace HiviewDFX
460 } // namepsace OHOS
461