1 /*
2 * Copyright (c) 2022-2023 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 <malloc.h>
20 #include <fcntl.h>
21 #include <securec.h>
22 #include <string>
23 #include <thread>
24 #include <unistd.h>
25 #include <vector>
26 #include <sys/prctl.h>
27 #include <sys/syscall.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <thread>
32
33 #include "dfx_define.h"
34 #include "dfx_signal_handler.h"
35 #include "dfx_signalhandler_exception.h"
36 #include "dfx_test_util.h"
37 #include "info/fatal_message.h"
38
39 using namespace testing;
40 using namespace testing::ext;
41 using namespace std;
42
43 namespace OHOS {
44 namespace HiviewDFX {
45 class SignalHandlerTest : public testing::Test {
46 public:
47 static void SetUpTestCase();
48 static void TearDownTestCase();
49 void SetUp();
50 void TearDown();
51 };
52
SetUpTestCase()53 void SignalHandlerTest::SetUpTestCase()
54 {}
55
TearDownTestCase()56 void SignalHandlerTest::TearDownTestCase()
57 {}
58
SetUp()59 void SignalHandlerTest::SetUp()
60 {}
61
TearDown()62 void SignalHandlerTest::TearDown()
63 {}
64
CheckCallbackCrashKeyWords(const string & filePath,pid_t pid,int sig)65 static bool CheckCallbackCrashKeyWords(const string& filePath, pid_t pid, int sig)
66 {
67 if (filePath.empty() || pid <= 0) {
68 return false;
69 }
70 map<int, string> sigKey = {
71 { SIGILL, string("SIGILL") },
72 { SIGBUS, string("SIGBUS") },
73 { SIGSEGV, string("SIGSEGV") },
74 };
75 string sigKeyword = "";
76 map<int, string>::iterator iter = sigKey.find(sig);
77 if (iter != sigKey.end()) {
78 sigKeyword = iter->second;
79 }
80 string keywords[] = {
81 "Pid:" + to_string(pid), "Uid:", "name:./test_signalhandler", sigKeyword,
82 "Tid:", "#00", "Registers:", "FaultStack:", "Maps:", "test_signalhandler"
83 };
84 int length = sizeof(keywords) / sizeof(keywords[0]);
85 int minRegIdx = -1;
86 return CheckKeyWords(filePath, keywords, length, minRegIdx) == length;
87 }
CheckCrashKeyWords(const string & filePath,pid_t pid,int sig)88 static bool CheckCrashKeyWords(const string& filePath, pid_t pid, int sig)
89 {
90 if (filePath.empty() || pid <= 0) {
91 return false;
92 }
93 map<int, string> sigKey = {
94 { SIGILL, string("SIGILL") },
95 { SIGBUS, string("SIGBUS") },
96 { SIGSEGV, string("SIGSEGV") },
97 { SIGABRT, string("SIGABRT") },
98 { SIGFPE, string("SIGFPE") },
99 { SIGSTKFLT, string("SIGSTKFLT") },
100 { SIGSYS, string("SIGSYS") },
101 { SIGTRAP, string("SIGTRAP") },
102 };
103 string sigKeyword = "";
104 map<int, string>::iterator iter = sigKey.find(sig);
105 if (iter != sigKey.end()) {
106 sigKeyword = iter->second;
107 }
108 string keywords[] = {
109 "Pid:" + to_string(pid), "Uid:", "name:./test_signalhandler", sigKeyword,
110 "Tid:", "#00", "Registers:", "FaultStack:", "Maps:", "test_signalhandler"
111 };
112 int length = sizeof(keywords) / sizeof(keywords[0]);
113 int minRegIdx = -1;
114 return CheckKeyWords(filePath, keywords, length, minRegIdx) == length;
115 }
116
CheckDebugSignalFaultlog(const string & filePath,pid_t pid,int siCode)117 static bool CheckDebugSignalFaultlog(const string& filePath, pid_t pid, int siCode)
118 {
119 if (filePath.empty() || pid <= 0) {
120 return false;
121 }
122 std::list<LineRule> rules;
123 rules.push_back(LineRule(R"(^Build info:.*$)"));
124 rules.push_back(LineRule(R"(^Process name:./test_signalhandler$)"));
125 rules.push_back(LineRule(R"(^Process life time:.*$)"));
126 rules.push_back(LineRule("^Pid:" + to_string(pid) + "$"));
127 rules.push_back(LineRule(R"(^Uid:\d+$)"));
128 rules.push_back(LineRule(R"(^Reason:Signal:DEBUG SIGNAL\((FDSAN|JEMALLOC|BADFD)\).*$)"));
129 rules.push_back(LineRule(R"(^#\d+ pc [0-9a-f]+ .*$)", 5)); // match 5 times
130 rules.push_back(LineRule(R"(^Registers:$)"));
131 rules.push_back(LineRule(R"(^FaultStack:$)"));
132 rules.push_back(LineRule(R"(^Maps:$)"));
133 if (siCode != SIGLEAK_STACK_BADFD) {
134 rules.push_back(LineRule(R"(^LastFatalMessage:.*$)"));
135 }
136 if (siCode != SIGLEAK_STACK_JEMALLOC) {
137 rules.push_back(LineRule(R"(^OpenFiles:$)"));
138 rules.push_back(LineRule(R"(^\d+->.*$)", 5)); // match 5 times
139 }
140 return CheckLineMatch(filePath, rules);
141 }
142
ThreadInfo(char * buf,size_t len,void * context)143 void ThreadInfo(char* buf, size_t len, void* context __attribute__((unused)))
144 {
145 char mes[] = "this is extraCrashInfo of test thread";
146 if (memcpy_s(buf, len, mes, sizeof(mes)) != 0) {
147 GTEST_LOG_(INFO) << "Failed to set thread info";
148 }
149 }
150
TestThread(int threadId,int sig)151 int TestThread(int threadId, int sig)
152 {
153 std::string subThreadName = "SubTestThread" + to_string(threadId);
154 prctl(PR_SET_NAME, subThreadName.c_str());
155 SetThreadInfoCallback(ThreadInfo);
156 int cashThreadId = 2;
157 if (threadId == cashThreadId) {
158 GTEST_LOG_(INFO) << subThreadName << " is ready to raise signo(" << sig <<")";
159 raise(sig);
160 }
161 return 0;
162 }
163
SaveDebugMessage(int siCode,int64_t diffMs,const char * msg)164 static void SaveDebugMessage(int siCode, int64_t diffMs, const char *msg)
165 {
166 const int signo = 42; // Custom stack capture signal and leak reuse
167 siginfo_t info;
168 info.si_signo = signo;
169 info.si_code = siCode;
170
171 debug_msg_t debug_message = {0, NULL};
172 if (msg != nullptr) {
173 const int numberOneThousand = 1000; // 1000 : second to millisecond convert ratio
174 const int numberOneMillion = 1000000; // 1000000 : nanosecond to millisecond convert ratio
175 struct timespec ts;
176 (void)clock_gettime(CLOCK_REALTIME, &ts);
177
178 uint64_t timestamp = static_cast<uint64_t>(ts.tv_sec) * numberOneThousand +
179 static_cast<uint64_t>(ts.tv_sec) / numberOneMillion;
180 if (diffMs < 0 && timestamp < -diffMs) {
181 timestamp = 0;
182 } else if (UINT64_MAX - timestamp < diffMs) {
183 timestamp = UINT64_MAX;
184 } else {
185 timestamp += diffMs;
186 }
187
188 debug_message.timestamp = timestamp;
189 debug_message.msg = msg;
190
191 info.si_value.sival_ptr = &debug_message;
192 }
193
194 if (syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid), signo, &info) == -1) {
195 GTEST_LOG_(ERROR) << "send failed errno=" << errno;
196 }
197 }
198
SendSigTestDebugSignal(int siCode)199 static bool SendSigTestDebugSignal(int siCode)
200 {
201 pid_t pid = fork();
202 if (pid < 0) {
203 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
204 return false;
205 }
206
207 if (pid == 0) {
208 SaveDebugMessage(siCode, 0, "test123");
209 sleep(5); // 5: wait for stacktrace generating
210 _exit(0);
211 }
212
213 sleep(2); // 2 : wait for cppcrash generating
214 return CheckDebugSignalFaultlog(GetDumpLogFileName("stacktrace", pid, TEMP_DIR), pid, siCode);
215 }
216
TestFdsan()217 static void TestFdsan()
218 {
219 fdsan_set_error_level(FDSAN_ERROR_LEVEL_WARN_ONCE);
220 FILE *fp = fopen("/dev/null", "w+");
221 if (fp == nullptr) {
222 GTEST_LOG_(ERROR) << "fp is nullptr";
223 return;
224 }
225 close(fileno(fp));
226 uint64_t tag = fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, reinterpret_cast<uint64_t>(fp));
227 fdsan_exchange_owner_tag(fileno(fp), tag, 0);
228 return;
229 }
230
TestBadfdThread(int maxCnt)231 void TestBadfdThread(int maxCnt)
232 {
233 for (int i = 0; i < maxCnt; i++) {
234 sleep(2); // Delay 2s waiting for the next triggerable cycle
235 SaveDebugMessage(SIGLEAK_STACK_BADFD, 0, nullptr);
236 }
237 }
238
239 /**
240 * @tc.name: SignalHandlerTest001
241 * @tc.desc: test thread cash SignalHandler signo(SIGILL)
242 * @tc.type: FUNC
243 */
244 HWTEST_F(SignalHandlerTest, SignalHandlerTest001, TestSize.Level0)
245 {
246 GTEST_LOG_(INFO) << "SignalHandlerTest001: start.";
247 pid_t pid = fork();
248 if (pid < 0) {
249 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
250 } else if (pid == 0) {
251 SetThreadInfoCallback(ThreadInfo);
252 sleep(1);
253 } else {
254 usleep(10000); // 10000 : sleep 10ms
255 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
256 kill(pid, SIGILL);
257 auto filename = WaitCreateCrashFile("cppcrash", pid);
258 bool ret = CheckCallbackCrashKeyWords(filename, pid, SIGILL);
259 ASSERT_TRUE(ret);
260 }
261 GTEST_LOG_(INFO) << "SignalHandlerTest001: end.";
262 }
263
264 /**
265 * @tc.name: SignalHandlerTest002
266 * @tc.desc: test thread cash SignalHandler signo(SIGBUS)
267 * @tc.type: FUNC
268 */
269 HWTEST_F(SignalHandlerTest, SignalHandlerTest002, TestSize.Level2)
270 {
271 GTEST_LOG_(INFO) << "SignalHandlerTest002: start.";
272 pid_t pid = fork();
273 if (pid < 0) {
274 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
275 } else if (pid == 0) {
276 SetThreadInfoCallback(ThreadInfo);
277 sleep(1);
278 } else {
279 usleep(10000); // 10000 : sleep 10ms
280 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
281 kill(pid, SIGBUS);
282 auto filename = WaitCreateCrashFile("cppcrash", pid);
283 bool ret = CheckCallbackCrashKeyWords(filename, pid, SIGBUS);
284 ASSERT_TRUE(ret);
285 }
286 GTEST_LOG_(INFO) << "SignalHandlerTest002: end.";
287 }
288
289 /**
290 * @tc.name: SignalHandlerTest003
291 * @tc.desc: test thread cash SignalHandler signo(SIGSEGV)
292 * @tc.type: FUNC
293 */
294 HWTEST_F(SignalHandlerTest, SignalHandlerTest003, TestSize.Level2)
295 {
296 GTEST_LOG_(INFO) << "SignalHandlerTest003: start.";
297 pid_t pid = fork();
298 if (pid < 0) {
299 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
300 } else if (pid == 0) {
301 SetThreadInfoCallback(ThreadInfo);
302 sleep(1);
303 } else {
304 usleep(10000); // 10000 : sleep 10ms
305 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
306 kill(pid, SIGSEGV);
307 auto filename = WaitCreateCrashFile("cppcrash", pid);
308 bool ret = CheckCallbackCrashKeyWords(filename, pid, SIGSEGV);
309 ASSERT_TRUE(ret);
310 }
311 GTEST_LOG_(INFO) << "SignalHandlerTest003: end.";
312 }
313
314 /**
315 * @tc.name: SignalHandlerTest004
316 * @tc.desc: test thread crash SignalHandler in multi-thread situation signo(SIGILL)
317 * @tc.type: FUNC
318 */
319 HWTEST_F(SignalHandlerTest, SignalHandlerTest004, TestSize.Level2)
320 {
321 GTEST_LOG_(INFO) << "SignalHandlerTest004: start.";
322 pid_t pid = fork();
323 if (pid < 0) {
324 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
325 } else if (pid == 0) {
326 std::thread (TestThread, 1, SIGILL).join(); // 1 : first thread
327 std::thread (TestThread, 2, SIGILL).join(); // 2 : second thread
328 _exit(0);
329 } else {
330 auto filename = WaitCreateCrashFile("cppcrash", pid);
331 bool ret = CheckCallbackCrashKeyWords(filename, pid, SIGILL);
332 ASSERT_TRUE(ret);
333 }
334 GTEST_LOG_(INFO) << "SignalHandlerTest004: end.";
335 }
336
337 /**
338 * @tc.name: SignalHandlerTest005
339 * @tc.desc: test thread crash SignalHandler in multi-thread situation signo(SIGBUS)
340 * @tc.type: FUNC
341 */
342 HWTEST_F(SignalHandlerTest, SignalHandlerTest005, TestSize.Level2)
343 {
344 GTEST_LOG_(INFO) << "SignalHandlerTest005: start.";
345 pid_t pid = fork();
346 if (pid < 0) {
347 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
348 } else if (pid == 0) {
349 std::thread (TestThread, 1, SIGBUS).join(); // 1 : first thread
350 std::thread (TestThread, 2, SIGBUS).join(); // 2 : second thread
351 _exit(0);
352 } else {
353 auto filename = WaitCreateCrashFile("cppcrash", pid);
354 bool ret = CheckCallbackCrashKeyWords(filename, pid, SIGBUS);
355 ASSERT_TRUE(ret);
356 }
357 GTEST_LOG_(INFO) << "SignalHandlerTest005: end.";
358 }
359
360 /**
361 * @tc.name: SignalHandlerTest006
362 * @tc.desc: test thread crash SignalHandler in multi-thread situation signo(SIGSEGV)
363 * @tc.type: FUNC
364 */
365 HWTEST_F(SignalHandlerTest, SignalHandlerTest006, TestSize.Level2)
366 {
367 GTEST_LOG_(INFO) << "SignalHandlerTest006: start.";
368 pid_t pid = fork();
369 if (pid < 0) {
370 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
371 } else if (pid == 0) {
372 std::thread (TestThread, 1, SIGSEGV).join(); // 1 : first thread
373 std::thread (TestThread, 2, SIGSEGV).join(); // 2 : second thread
374 _exit(0);
375 } else {
376 auto filename = WaitCreateCrashFile("cppcrash", pid);
377 bool ret = CheckCallbackCrashKeyWords(filename, pid, SIGSEGV);
378 ASSERT_TRUE(ret);
379 }
380 GTEST_LOG_(INFO) << "SignalHandlerTest006: end.";
381 }
382
383 /**
384 * @tc.name: SignalHandlerTest007
385 * @tc.desc: test DFX_InstallSignalHandler interface
386 * @tc.type: FUNC
387 */
388 HWTEST_F(SignalHandlerTest, SignalHandlerTest007, TestSize.Level2)
389 {
390 GTEST_LOG_(INFO) << "SignalHandlerTest007: start.";
391 int interestedSignalList[] = {
392 SIGABRT, SIGBUS, SIGFPE,
393 SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
394 };
395 for (int sig : interestedSignalList) {
396 pid_t pid = fork();
397 if (pid < 0) {
398 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
399 } else if (pid == 0) {
400 sleep(1);
401 } else {
402 usleep(10000); // 10000 : sleep 10ms
403 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill << process(" << pid << ")";
404 GTEST_LOG_(INFO) << "signal:" << sig;
405 kill(pid, sig);
406 auto filename = WaitCreateCrashFile("cppcrash", pid);
407 bool ret = CheckCrashKeyWords(filename, pid, sig);
408 ASSERT_TRUE(ret);
409 }
410 }
411 GTEST_LOG_(INFO) << "SignalHandlerTest007: end.";
412 }
413
TestThread2(int threadId,int sig,int total,bool exitEarly)414 int TestThread2(int threadId, int sig, int total, bool exitEarly)
415 {
416 std::string subThreadName = "SubTestThread" + to_string(threadId);
417 prctl(PR_SET_NAME, subThreadName.c_str());
418 SetThreadInfoCallback(ThreadInfo);
419
420 if (threadId == total - 1) {
421 GTEST_LOG_(INFO) << subThreadName << " is ready to raise signo(" << sig <<")";
422 raise(sig);
423 }
424
425 if (!exitEarly) {
426 sleep(total - threadId);
427 }
428 SetThreadInfoCallback(ThreadInfo);
429
430 return 0;
431 }
432
433 /**
434 * @tc.name: SignalHandlerTest008
435 * @tc.desc: test add 36 thread info callback and crash thread has no callback
436 * @tc.type: FUNC
437 */
438 HWTEST_F(SignalHandlerTest, SignalHandlerTest008, TestSize.Level2)
439 {
440 GTEST_LOG_(INFO) << "SignalHandlerTest008: start.";
441 pid_t pid = fork();
442 if (pid < 0) {
443 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
444 } else if (pid == 0) {
445 std::vector<std::thread> threads;
446 const int testThreadCount = 36;
447 for (int i = 0; i < testThreadCount; i++) {
448 threads.push_back(std::thread(TestThread2, i, SIGSEGV, testThreadCount, false));
449 }
450
451 for (auto& thread : threads) {
452 thread.join();
453 }
454 _exit(0);
455 } else {
456 auto file = WaitCreateCrashFile("cppcrash", pid);
457 ASSERT_FALSE(file.empty());
458 }
459 GTEST_LOG_(INFO) << "SignalHandlerTest008: end.";
460 }
461
462 /**
463 * @tc.name: SignalHandlerTest009
464 * @tc.desc: test add 36 thread info callback and crash thread has the callback
465 * @tc.type: FUNC
466 */
467 HWTEST_F(SignalHandlerTest, SignalHandlerTest009, TestSize.Level2)
468 {
469 GTEST_LOG_(INFO) << "SignalHandlerTest009: start.";
470 pid_t pid = fork();
471 if (pid < 0) {
472 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
473 } else if (pid == 0) {
474 std::vector<std::thread> threads;
475 const int testThreadCount = 36;
476 for (int i = 0; i < testThreadCount; i++) {
477 bool exitEarly = false;
478 if (i % 2 == 0) {
479 exitEarly = true;
480 }
481 threads.push_back(std::thread (TestThread2, i, SIGSEGV, testThreadCount, exitEarly));
482 }
483
484 for (auto& thread : threads) {
485 thread.join();
486 }
487 _exit(0);
488 } else {
489 auto file = WaitCreateCrashFile("cppcrash", pid);
490 ASSERT_FALSE(file.empty());
491 }
492 GTEST_LOG_(INFO) << "SignalHandlerTest009: end.";
493 }
494
495 /**
496 * @tc.name: SignalHandlerTest010
497 * @tc.desc: test crash when free a invalid address
498 * @tc.type: FUNC
499 */
500 HWTEST_F(SignalHandlerTest, SignalHandlerTest010, TestSize.Level2)
501 {
502 GTEST_LOG_(INFO) << "SignalHandlerTest010: start.";
503 pid_t pid = fork();
504 if (pid < 0) {
505 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
506 } else if (pid == 0) {
507 SetThreadInfoCallback(ThreadInfo);
508 int32_t freeAddr = 0x111;
509 // trigger crash
510 free(reinterpret_cast<void*>(freeAddr));
511 // force crash if not crash in free
512 abort();
513 } else {
514 auto file = WaitCreateCrashFile("cppcrash", pid);
515 ASSERT_FALSE(file.empty());
516 }
517 GTEST_LOG_(INFO) << "SignalHandlerTest010: end.";
518 }
519
520 /**
521 * @tc.name: SignalHandlerTest011
522 * @tc.desc: test crash when realloc a invalid address
523 * @tc.type: FUNC
524 */
525 HWTEST_F(SignalHandlerTest, SignalHandlerTest011, TestSize.Level2)
526 {
527 GTEST_LOG_(INFO) << "SignalHandlerTest011: start.";
528 pid_t pid = fork();
529 if (pid < 0) {
530 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
531 } else if (pid == 0) {
532 int32_t initAllocSz = 10;
533 int32_t reallocSz = 20;
534 SetThreadInfoCallback(ThreadInfo);
535 // alloc a buffer
536 int8_t* addr = reinterpret_cast<int8_t*>(malloc(initAllocSz));
537 // overwrite the control block
538 int8_t* newAddr = addr - initAllocSz;
539 (void)memset_s(newAddr, initAllocSz, 0, initAllocSz);
540 addr = reinterpret_cast<int8_t*>(realloc(reinterpret_cast<void*>(addr), reallocSz));
541 free(addr);
542 // force crash if not crash in realloc
543 abort();
544 } else {
545 auto file = WaitCreateCrashFile("cppcrash", pid);
546 ASSERT_FALSE(file.empty());
547 }
548 GTEST_LOG_(INFO) << "SignalHandlerTest011: end.";
549 }
550
551 /**
552 * @tc.name: SignalHandlerTest012
553 * @tc.desc: test crash when realloc a invalid address without threadInfo callback
554 * @tc.type: FUNC
555 */
556 HWTEST_F(SignalHandlerTest, SignalHandlerTest012, TestSize.Level2)
557 {
558 GTEST_LOG_(INFO) << "SignalHandlerTest012: start.";
559 pid_t pid = fork();
560 if (pid < 0) {
561 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
562 } else if (pid == 0) {
563 int32_t initAllocSz = 10;
564 int32_t reallocSz = 20;
565 // alloc a buffer
566 int8_t* addr = reinterpret_cast<int8_t*>(malloc(initAllocSz));
567 // overwrite the control block
568 int8_t* newAddr = addr - initAllocSz;
569 (void)memset_s(newAddr, initAllocSz, 0, initAllocSz);
570 addr = reinterpret_cast<int8_t*>(realloc(reinterpret_cast<void*>(addr), reallocSz));
571 free(addr);
572 // force crash if not crash in realloc
573 abort();
574 } else {
575 auto file = WaitCreateCrashFile("cppcrash", pid);
576 ASSERT_FALSE(file.empty());
577 }
578 GTEST_LOG_(INFO) << "SignalHandlerTest012: end.";
579 }
580
581 /**
582 * @tc.name: SignalHandlerTest013
583 * @tc.desc: test add 100 thread info callback and do nothing
584 * @tc.type: FUNC
585 */
586 HWTEST_F(SignalHandlerTest, SignalHandlerTest013, TestSize.Level2)
587 {
588 GTEST_LOG_(INFO) << "SignalHandlerTest013: start.";
589 std::vector<std::thread> threads;
590 const int testThreadCount = 100;
591 for (int i = 0; i < testThreadCount - 1; i++) {
592 threads.push_back(std::thread (TestThread2, i, SIGSEGV, testThreadCount, true));
593 }
594
595 for (auto& thread : threads) {
596 if (thread.joinable()) {
597 thread.join();
598 }
599 }
600 auto file = GetCppCrashFileName(getpid());
601 ASSERT_TRUE(file.empty());
602 GTEST_LOG_(INFO) << "SignalHandlerTest013: end.";
603 }
604
TestCallbackFunc()605 uint64_t TestCallbackFunc()
606 {
607 return 0;
608 }
609
610 /**
611 * @tc.name: SignalHandlerTest015
612 * @tc.desc: test DFX_SetAppRunningUniqueId
613 * @tc.type: FUNC
614 */
615 HWTEST_F(SignalHandlerTest, SignalHandlerTest015, TestSize.Level2)
616 {
617 bool isSuccess = true;
618 if (!isSuccess) {
619 ASSERT_FALSE(isSuccess);
620 } else {
621 /**
622 * @tc.steps: step1.
623 * case: appRunningId == nullptr, len= 0
624 * @tc.expected: ret == -1
625 * */
626 int ret = DFX_SetAppRunningUniqueId(nullptr, 0);
627 ASSERT_EQ(ret, -1);
628
629 /**
630 * @tc.steps: step2.
631 * case: appRunningId == nullptr, len= MAX_APP_RUNNING_UNIQUE_ID_LEN
632 * @tc.expected: ret == -1
633 * */
634 ret = DFX_SetAppRunningUniqueId(nullptr, MAX_APP_RUNNING_UNIQUE_ID_LEN);
635 ASSERT_EQ(ret, -1);
636
637 /**
638 * @tc.steps: step3.
639 * case: appRunningId != nullptr, len= 0
640 * @tc.expected: ret == 0
641 * */
642 constexpr char testId1[] = "App running unique test id";
643 ret = DFX_SetAppRunningUniqueId(testId1, 0);
644 ASSERT_EQ(ret, 0);
645
646 /**
647 * @tc.steps: step4.
648 * case: appRunningId != nullptr, len= strleng(appRunningId)
649 * @tc.expected: ret == 0
650 * */
651 ret = DFX_SetAppRunningUniqueId(testId1, strlen(testId1));
652 ASSERT_EQ(ret, 0);
653
654 /**
655 * @tc.steps: step5.
656 * case: appRunningId != nullptr, len= MAX_APP_RUNNING_UNIQUE_ID_LEN + 1
657 * @tc.expected: ret == -1
658 * */
659 constexpr size_t testLen = MAX_APP_RUNNING_UNIQUE_ID_LEN + 1;
660 ret = DFX_SetAppRunningUniqueId(testId1, testLen);
661 ASSERT_EQ(ret, -1);
662
663 /**
664 * @tc.steps: step6.
665 * case: appRunningId != nullptr, len= MAX_APP_RUNNING_UNIQUE_ID_LEN
666 * @tc.expected: ret == 0
667 * */
668 constexpr char testId2[MAX_APP_RUNNING_UNIQUE_ID_LEN] = "App running unique test id";
669 ret = DFX_SetAppRunningUniqueId(testId2, MAX_APP_RUNNING_UNIQUE_ID_LEN);
670 ASSERT_EQ(ret, -1);
671 }
672 }
673
674 /**
675 * @tc.name: SignalHandlerTest016
676 * @tc.desc: test ReportException
677 * @tc.type: FUNC
678 */
679 HWTEST_F(SignalHandlerTest, SignalHandlerTest016, TestSize.Level2)
680 {
681 GTEST_LOG_(INFO) << "SignalHandlerTest016: start.";
682 DFX_SetAsyncStackCallback(TestCallbackFunc);
683
684 struct CrashDumpException exception;
685 exception.pid = 1;
686 exception.uid = 1;
687 exception.error = CRASH_SIGNAL_EMASKED;
688 int ret = ReportException(&exception);
689 ASSERT_NE(ret, -1);
690 GTEST_LOG_(INFO) << "SignalHandlerTest016: end.";
691 }
692
693 /**
694 * @tc.name: SignalHandlerTest017
695 * @tc.desc: send sig SIGLEAK_STACK_FDSAN
696 * @tc.type: FUNC
697 */
698 HWTEST_F(SignalHandlerTest, SignalHandlerTest017, TestSize.Level2)
699 {
700 std::string res = ExecuteCommands("uname");
701 bool linuxKernel = res.find("Linux") != std::string::npos;
702 if (linuxKernel) {
703 ASSERT_TRUE(linuxKernel);
704 } else {
705 bool ret = SendSigTestDebugSignal(SIGLEAK_STACK_FDSAN);
706 ASSERT_TRUE(ret);
707 }
708 }
709
710 /**
711 * @tc.name: SignalHandlerTest018
712 * @tc.desc: send sig SIGLEAK_STACK_JEMALLOC
713 * @tc.type: FUNC
714 */
715 HWTEST_F(SignalHandlerTest, SignalHandlerTest018, TestSize.Level2)
716 {
717 std::string res = ExecuteCommands("uname");
718 bool linuxKernel = res.find("Linux") != std::string::npos;
719 if (linuxKernel) {
720 ASSERT_TRUE(linuxKernel);
721 } else {
722 bool ret = SendSigTestDebugSignal(SIGLEAK_STACK_JEMALLOC);
723 ASSERT_TRUE(ret);
724 }
725 }
726
727 /**
728 * @tc.name: SignalHandlerTest019
729 * @tc.desc: send sig SIGLEAK_STACK_BADFD
730 * @tc.type: FUNC
731 */
732 HWTEST_F(SignalHandlerTest, SignalHandlerTest019, TestSize.Level2)
733 {
734 std::string res = ExecuteCommands("uname");
735 bool linuxKernel = res.find("Linux") != std::string::npos;
736 if (linuxKernel) {
737 ASSERT_TRUE(linuxKernel);
738 } else {
739 bool ret = SendSigTestDebugSignal(SIGLEAK_STACK_BADFD);
740 ASSERT_TRUE(ret);
741 }
742 }
743
744 /**
745 * @tc.name: SignalHandlerTest020
746 * @tc.desc: test DEBUG SIGNAL time out, BADFD no timeout
747 * @tc.type: FUNC
748 */
749 HWTEST_F(SignalHandlerTest, SignalHandlerTest020, TestSize.Level2)
750 {
751 std::string res = ExecuteCommands("uname");
752 bool linuxKernel = res.find("Linux") != std::string::npos;
753 if (linuxKernel) {
754 ASSERT_TRUE(linuxKernel);
755 } else {
756 int interestedSiCodeList[] = {
757 SIGLEAK_STACK_FDSAN, SIGLEAK_STACK_JEMALLOC
758 };
759 for (int siCode : interestedSiCodeList) {
760 pid_t pid = fork();
761 if (pid < 0) {
762 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
763 } else if (pid == 0) {
764 constexpr int diffMs = -10000; // 10s
765 SaveDebugMessage(siCode, diffMs, "test123");
766 sleep(5); // 5: wait for stacktrace generating
767 _exit(0);
768 } else {
769 auto fileName = WaitCreateCrashFile("stacktrace", pid);
770 ASSERT_TRUE(fileName.empty());
771 }
772 }
773 }
774 }
775
776 /**
777 * @tc.name: SignalHandlerTest021
778 * @tc.desc: test FDSAN
779 * @tc.type: FUNC
780 */
781 HWTEST_F(SignalHandlerTest, SignalHandlerTest021, TestSize.Level2)
782 {
783 std::string res = ExecuteCommands("uname");
784 bool linuxKernel = res.find("Linux") != std::string::npos;
785 if (linuxKernel) {
786 ASSERT_TRUE(linuxKernel);
787 } else {
788 pid_t pid = fork();
789 if (pid < 0) {
790 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
791 } else if (pid == 0) {
792 TestFdsan();
793 sleep(5); // 5: wait for stacktrace generating
794 _exit(0);
795 } else {
796 constexpr int siCode = SIGLEAK_STACK_FDSAN;
797 auto fileName = WaitCreateCrashFile("stacktrace", pid);
798 bool ret = CheckDebugSignalFaultlog(fileName, pid, siCode);
799 ASSERT_TRUE(ret);
800 }
801 }
802 }
803
804 /**
805 * @tc.name: SignalHandlerTest022
806 * @tc.desc: test BADFD
807 * @tc.type: FUNC
808 */
809 HWTEST_F(SignalHandlerTest, SignalHandlerTest022, TestSize.Level2)
810 {
811 std::string res = ExecuteCommands("uname");
812 bool linuxKernel = res.find("Linux") != std::string::npos;
813 if (linuxKernel) {
814 ASSERT_TRUE(linuxKernel);
815 } else {
816 pid_t pid = fork();
817 if (pid < 0) {
818 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
819 } else if (pid == 0) {
820 SaveDebugMessage(SIGLEAK_STACK_BADFD, 0, nullptr);
821 sleep(5); // 5: wait for stacktrace generating
822 _exit(0);
823 } else {
824 constexpr int siCode = SIGLEAK_STACK_BADFD;
825 auto fileName = WaitCreateCrashFile("stacktrace", pid);
826 bool ret = CheckDebugSignalFaultlog(fileName, pid, siCode);
827 ASSERT_TRUE(ret);
828 }
829 }
830 }
831
832 /**
833 * @tc.name: SignalHandlerTest023
834 * @tc.desc: test BADFD
835 * @tc.type: FUNC
836 */
837 HWTEST_F(SignalHandlerTest, SignalHandlerTest023, TestSize.Level2)
838 {
839 std::string res = ExecuteCommands("uname");
840 bool linuxKernel = res.find("Linux") != std::string::npos;
841 if (linuxKernel) {
842 ASSERT_TRUE(linuxKernel);
843 } else {
844 constexpr int maxCnt = 3; // Run the test 3 times
845 std::thread testBadfdThread(TestBadfdThread, maxCnt);
846 for (int i = 0; i < maxCnt; i++) {
847 auto fileName = WaitCreateCrashFile("stacktrace", getpid());
848 ASSERT_TRUE(!fileName.empty());
849 }
850 testBadfdThread.join();
851 }
852 }
853
854 /**
855 * @tc.name: SignalHandlerTest024
856 * @tc.desc: test DFX_GetAppRunningUniqueId
857 * @tc.type: FUNC
858 */
859 HWTEST_F(SignalHandlerTest, SignalHandlerTest024, TestSize.Level2)
860 {
861 constexpr char testId[] = "App running unique id";
862 int ret = DFX_SetAppRunningUniqueId(testId, strlen(testId));
863 ASSERT_EQ(ret, 0);
864 const char* runningId = DFX_GetAppRunningUniqueId();
865 ASSERT_STREQ(runningId, testId);
866 }
867
868 /**
869 * @tc.name: FdTableTest001
870 * @tc.desc: Verify the fdtable structure
871 * @tc.type: FUNC
872 */
873 HWTEST_F(SignalHandlerTest, FdTableTest001, TestSize.Level2)
874 {
875 std::string res = ExecuteCommands("uname");
876 bool linuxKernel = res.find("Linux") != std::string::npos;
877 if (linuxKernel) {
878 ASSERT_TRUE(linuxKernel);
879 } else {
880 /**
881 * @tc.steps: step1. open 128 fd files
882 * case: open success
883 * @tc.expected: fp != nullptr
884 * */
885 constexpr int maxOpenNum = 128; // open fd table
886 FILE* fdList[maxOpenNum] = {nullptr};
887 for (int i = 0; i < maxOpenNum; i++) {
888 fdList[i] = fopen("/dev/null", "r");
889 ASSERT_NE(fdList[i], nullptr);
890 }
891
892 /**
893 * @tc.steps: step2. open test fd
894 * case: open success
895 * @tc.expected: fp != nullptr
896 * */
897 FILE *fp = fopen("/dev/null", "r");
898 ASSERT_NE(fp, nullptr);
899
900 /**
901 * @tc.steps: step3. Clean up resources
902 * */
903 for (int i = 0; i < maxOpenNum; i++) {
904 if (fdList[i] != nullptr) {
905 fclose(fdList[i]);
906 fdList[i] = nullptr;
907 }
908 }
909
910 /**
911 * @tc.steps: step4. Get fd tag
912 * */
913 uint64_t ownerTag = fdsan_get_owner_tag(fileno(fp));
914 uint64_t tag = fdsan_get_tag_value(ownerTag);
915
916 pid_t pid = fork();
917 if (pid < 0) {
918 GTEST_LOG_(ERROR) << "Failed to fork new process.";
919 } else if (pid == 0) {
920 // The child process has disabled fdsan detection by default
921 fdsan_set_error_level(FDSAN_ERROR_LEVEL_WARN_ONCE);
922 /**
923 * @tc.steps: step5. Trigger fdsan
924 * */
925 close(fileno(fp));
926 } else {
927 /**
928 * @tc.steps: step6. Waiting for the completion of stack grabbing
929 * */
930 sleep(3); // 3 : sleep 3 seconds
931
932 string keywords[] = {
933 to_string(fileno(fp)) + "->/dev/null", to_string(tag)
934 };
935 fclose(fp);
936
937 /**
938 * @tc.steps: step7. Check key words
939 * @tc.expected: check success
940 * */
941 auto filePath = GetDumpLogFileName("stacktrace", pid, TEMP_DIR);
942 ASSERT_FALSE(filePath.empty());
943
944 int length = sizeof(keywords) / sizeof(keywords[0]);
945 int minRegIdx = -1;
946 ASSERT_EQ(CheckKeyWords(filePath, keywords, length, minRegIdx), length);
947 }
948 }
949 }
950
951 /**
952 * @tc.name: SetCrashLogConfig001
953 * @tc.desc: Verify the set crash Log config
954 * @tc.type: FUNC
955 */
956 HWTEST_F(SignalHandlerTest, SetCrashLogConfig001, TestSize.Level2)
957 {
958 pid_t pid = fork();
959 if (pid < 0) {
960 GTEST_LOG_(ERROR) << "Failed to fork new process.";
961 } else if (pid == 0) {
962 ASSERT_EQ(DFX_SetCrashLogConfig(0, 1), 0);
963 ASSERT_EQ(DFX_SetCrashLogConfig(1, 10000), 0);
964 ASSERT_EQ(DFX_SetCrashLogConfig(2, 1), 0);
965 abort();
966 } else {
967 sleep(3); // 3 : sleep 3 seconds
968 string keywords[] = {
969 "configs:",
970 "printing:true",
971 "size:10000B",
972 "printing:true",
973 };
974 auto filePath = GetDumpLogFileName("cppcrash", pid, TEMP_DIR);
975 ASSERT_FALSE(filePath.empty());
976
977 int length = sizeof(keywords) / sizeof(keywords[0]);
978 int minRegIdx = -1;
979 ASSERT_EQ(CheckKeyWords(filePath, keywords, length, minRegIdx), length);
980 }
981 }
982
983 /**
984 * @tc.name: SetCrashLogConfig002
985 * @tc.desc: Verify the set crash Log config twice
986 * @tc.type: FUNC
987 */
988 HWTEST_F(SignalHandlerTest, SetCrashLogConfig002, TestSize.Level2)
989 {
990 pid_t pid = fork();
991 if (pid < 0) {
992 GTEST_LOG_(ERROR) << "Failed to fork new process.";
993 } else if (pid == 0) {
994 // once
995 ASSERT_EQ(DFX_SetCrashLogConfig(0, 1), 0);
996 ASSERT_EQ(DFX_SetCrashLogConfig(1, 10000), 0);
997 ASSERT_EQ(DFX_SetCrashLogConfig(2, 1), 0);
998 // twice
999 ASSERT_EQ(DFX_SetCrashLogConfig(0, 0), 0);
1000 ASSERT_EQ(DFX_SetCrashLogConfig(1, 9999), 0);
1001 ASSERT_EQ(DFX_SetCrashLogConfig(2, 1), 0);
1002 abort();
1003 } else {
1004 sleep(3); // 3 : sleep 3 seconds
1005 string keywords[] = {
1006 "configs:",
1007 "size:9999B",
1008 "printing:true",
1009 };
1010 auto filePath = GetDumpLogFileName("cppcrash", pid, TEMP_DIR);
1011 ASSERT_FALSE(filePath.empty());
1012
1013 int length = sizeof(keywords) / sizeof(keywords[0]);
1014 int minRegIdx = -1;
1015 ASSERT_EQ(CheckKeyWords(filePath, keywords, length, minRegIdx), length);
1016 }
1017 }
1018
1019 /**
1020 * @tc.name: SetCrashLogConfig003
1021 * @tc.desc: Verify the set crash Log config three times
1022 * @tc.type: FUNC
1023 */
1024 HWTEST_F(SignalHandlerTest, SetCrashLogConfig003, TestSize.Level2)
1025 {
1026 pid_t pid = fork();
1027 if (pid < 0) {
1028 GTEST_LOG_(ERROR) << "Failed to fork new process.";
1029 } else if (pid == 0) {
1030 // once
1031 ASSERT_EQ(DFX_SetCrashLogConfig(0, 1), 0);
1032 ASSERT_EQ(DFX_SetCrashLogConfig(1, 10000), 0);
1033 ASSERT_EQ(DFX_SetCrashLogConfig(2, 1), 0);
1034 // twice
1035 ASSERT_EQ(DFX_SetCrashLogConfig(0, 0), 0);
1036 ASSERT_EQ(DFX_SetCrashLogConfig(1, 9999), 0);
1037 ASSERT_EQ(DFX_SetCrashLogConfig(2, 1), 0);
1038 // three times
1039 ASSERT_EQ(DFX_SetCrashLogConfig(0, 1), 0);
1040 ASSERT_EQ(DFX_SetCrashLogConfig(1, 1024), 0);
1041 ASSERT_EQ(DFX_SetCrashLogConfig(2, 0), 0);
1042 abort();
1043 } else {
1044 sleep(3); // 3 : sleep 3 seconds
1045 string keywords[] = {
1046 "configs:",
1047 "printing:true",
1048 "size:1024B",
1049 };
1050 auto filePath = GetDumpLogFileName("cppcrash", pid, TEMP_DIR);
1051 ASSERT_FALSE(filePath.empty());
1052
1053 int length = sizeof(keywords) / sizeof(keywords[0]);
1054 int minRegIdx = -1;
1055 ASSERT_EQ(CheckKeyWords(filePath, keywords, length, minRegIdx), length);
1056 }
1057 }
1058 } // namespace HiviewDFX
1059 } // namepsace OHOS
1060