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