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