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