1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <gtest/gtest.h>
17#include <csignal>
18#include <map>
19#include <securec.h>
20#include <string>
21#include <thread>
22#include <unistd.h>
23#include <vector>
24#include <sys/prctl.h>
25
26#include "dfx_define.h"
27#include "dfx_signal_local_handler.h"
28#include "dfx_socket_request.h"
29#include "dfx_test_util.h"
30#include "dfx_allocator.h"
31#include "faultloggerd_client.h"
32
33#define MALLOC_TEST_TIMES  1000
34#define MALLOC_TEST_SMALL_SIZE 16
35#define MALLOC_TEST_BIG_SIZE 2000
36
37using namespace testing;
38using namespace testing::ext;
39using namespace std;
40
41namespace OHOS {
42namespace HiviewDFX {
43class LocalHandlerTest : public testing::Test {
44public:
45    static void SetUpTestCase();
46    static void TearDownTestCase();
47    void SetUp();
48    void TearDown();
49};
50
51void LocalHandlerTest::SetUpTestCase()
52{}
53
54void LocalHandlerTest::TearDownTestCase()
55{}
56
57void LocalHandlerTest::SetUp()
58{}
59
60void LocalHandlerTest::TearDown()
61{}
62
63static bool CheckLocalCrashKeyWords(const string& filePath, pid_t pid, int sig)
64{
65    if (filePath.empty() || pid <= 0) {
66        return false;
67    }
68    map<int, string> sigKey = {
69        { SIGILL, string("Signal(4)") },
70        { SIGABRT, string("Signal(6)") },
71        { SIGBUS, string("Signal(7)") },
72        { SIGSEGV, string("Signal(11)") },
73    };
74    string sigKeyword = "";
75    map<int, string>::iterator iter = sigKey.find(sig);
76    if (iter != sigKey.end()) {
77        sigKeyword = iter->second;
78    }
79#ifdef __aarch64__
80    string keywords[] = {
81        "Pid:" + to_string(pid), "Uid:", "name:./test_localhandler",
82        sigKeyword, "Tid:", "#00", "x0:", "test_localhandler"
83    };
84#else
85    string keywords[] = {
86        "Pid:" + to_string(pid), "Uid:", "name:./test_localhandler",
87        sigKeyword, "Tid:", "#00", "test_localhandler"
88    };
89#endif
90
91    int length = sizeof(keywords) / sizeof(keywords[0]);
92    int minRegIdx = -1;
93    return CheckKeyWords(filePath, keywords, length, minRegIdx) == length;
94}
95
96/**
97 * @tc.name: LocalHandlerTest001
98 * @tc.desc: test crashlocalhandler signo(SIGILL)
99 * @tc.type: FUNC
100 */
101HWTEST_F(LocalHandlerTest, LocalHandlerTest001, TestSize.Level2)
102{
103    GTEST_LOG_(INFO) << "LocalHandlerTest001: start.";
104    pid_t pid = fork();
105    if (pid < 0) {
106        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
107    } else if (pid == 0) {
108        DFX_InstallLocalSignalHandler();
109        sleep(1);
110    } else {
111        usleep(10000); // 10000 : sleep 10ms
112        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
113        kill(pid, SIGILL);
114        sleep(2); // 2 : wait for cppcrash generating
115        bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGILL);
116        ASSERT_TRUE(ret);
117    }
118    GTEST_LOG_(INFO) << "LocalHandlerTest001: end.";
119}
120
121/**
122 * @tc.name: LocalHandlerTest002
123 * @tc.desc: test crashlocalhandler signo(SIGABRT)
124 * @tc.type: FUNC
125 */
126HWTEST_F(LocalHandlerTest, LocalHandlerTest002, TestSize.Level2)
127{
128    GTEST_LOG_(INFO) << "LocalHandlerTest002: start.";
129    pid_t pid = fork();
130    if (pid < 0) {
131        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
132    } else if (pid == 0) {
133        DFX_InstallLocalSignalHandler();
134        sleep(1);
135    } else {
136        usleep(10000); // 10000 : sleep 10ms
137        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
138        kill(pid, SIGABRT);
139        sleep(2); // 2 : wait for cppcrash generating
140        bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGABRT);
141        ASSERT_TRUE(ret);
142    }
143    GTEST_LOG_(INFO) << "LocalHandlerTest002: end.";
144}
145
146/**
147 * @tc.name: LocalHandlerTest003
148 * @tc.desc: test crashlocalhandler signo(SIGBUS)
149 * @tc.type: FUNC
150 */
151HWTEST_F(LocalHandlerTest, LocalHandlerTest003, TestSize.Level2)
152{
153    GTEST_LOG_(INFO) << "LocalHandlerTest003: start.";
154    pid_t pid = fork();
155    if (pid < 0) {
156        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
157    } else if (pid == 0) {
158        DFX_InstallLocalSignalHandler();
159        sleep(1);
160    } else {
161        usleep(10000); // 10000 : sleep 10ms
162        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
163        kill(pid, SIGBUS);
164        sleep(2); // 2 : wait for cppcrash generating
165        bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGBUS);
166        ASSERT_TRUE(ret);
167    }
168    GTEST_LOG_(INFO) << "LocalHandlerTest003: end.";
169}
170
171/**
172 * @tc.name: LocalHandlerTest004
173 * @tc.desc: test crashlocalhandler signo(SIGSEGV)
174 * @tc.type: FUNC
175 */
176HWTEST_F(LocalHandlerTest, LocalHandlerTest004, TestSize.Level2)
177{
178    GTEST_LOG_(INFO) << "LocalHandlerTest004: start.";
179    pid_t pid = fork();
180    if (pid < 0) {
181        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
182    } else if (pid == 0) {
183        DFX_InstallLocalSignalHandler();
184        sleep(1);
185    } else {
186        usleep(10000); // 10000 : sleep 10ms
187        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
188        kill(pid, SIGSEGV);
189        sleep(2); // 2 : wait for cppcrash generating
190        bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
191        ASSERT_TRUE(ret);
192    }
193    GTEST_LOG_(INFO) << "LocalHandlerTest004: end.";
194}
195
196/**
197 * @tc.name: LocalHandlerTest005
198 * @tc.desc: test crashlocalhandler signo(SIGSEGV) by execl
199 * @tc.type: FUNC
200 */
201HWTEST_F(LocalHandlerTest, LocalHandlerTest005, TestSize.Level2)
202{
203    GTEST_LOG_(INFO) << "LocalHandlerTest005: start.";
204    pid_t pid = fork();
205    if (pid < 0) {
206        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
207    } else if (pid == 0) {
208        DFX_InstallLocalSignalHandler();
209        sleep(1);
210        raise(SIGSEGV);
211    } else {
212        usleep(10000); // 10000 : sleep 10ms
213        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")";
214        sleep(2); // 2 : wait for cppcrash generating
215        bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
216        ASSERT_TRUE(ret);
217    }
218    GTEST_LOG_(INFO) << "LocalHandlerTest005: end.";
219}
220
221/**
222 * @tc.name: LocalHandlerTest006
223 * @tc.desc: test crashlocalhandler signo(SIGSEGV) by execl
224 * @tc.type: FUNC
225 */
226HWTEST_F(LocalHandlerTest, LocalHandlerTest006, TestSize.Level2)
227{
228    GTEST_LOG_(INFO) << "LocalHandlerTest006: start.";
229    pid_t pid = fork();
230    if (pid < 0) {
231        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
232    } else if (pid == 0) {
233        siginfo_t siginfo {
234            .si_signo = SIGSEGV
235        };
236        DFX_SignalLocalHandler(SIGSEGV, &siginfo, nullptr);
237    } else {
238        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")";
239        sleep(2); // 2 : wait for cppcrash generating
240        ASSERT_TRUE(CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV));
241    }
242    GTEST_LOG_(INFO) << "LocalHandlerTest006: end.";
243}
244
245/**
246 * @tc.name: LocalHandlerTest007
247 * @tc.desc: test crashlocalhandler signo(SIGSEGV) by execl
248 * @tc.type: FUNC
249 */
250HWTEST_F(LocalHandlerTest, LocalHandlerTest007, TestSize.Level2)
251{
252    GTEST_LOG_(INFO) << "LocalHandlerTest005: start.";
253    pid_t pid = fork();
254    if (pid < 0) {
255        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
256    } else if (pid == 0) {
257        siginfo_t siginfo {
258            .si_signo = SIGSEGV
259        };
260        DFX_GetCrashFdFunc([]{return RequestFileDescriptor((int)FaultLoggerType::CPP_CRASH);});
261        DFX_SignalLocalHandler(SIGSEGV, &siginfo, nullptr);
262    } else {
263        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")";
264        sleep(2); // 2 : wait for cppcrash generating
265        bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
266        ASSERT_TRUE(ret);
267    }
268    GTEST_LOG_(INFO) << "LocalHandlerTest007: end.";
269}
270
271/**
272 * @tc.name: DfxAllocatorTest001
273 * @tc.desc: test dfxAllocator isDfxAllocatorMem
274 * @tc.type: FUNC
275 */
276HWTEST_F(LocalHandlerTest, DfxAllocatorTest001, TestSize.Level2)
277{
278    GTEST_LOG_(INFO) << "DfxAllocatorTest001: start.";
279    void* p = malloc(MALLOC_TEST_SMALL_SIZE);
280    int ret = 0;
281    if (p) {
282        ret = IsDfxAllocatorMem(p);
283        free(p);
284    }
285    ASSERT_TRUE(ret == 0);
286    GTEST_LOG_(INFO) << "DfxAllocatorTest001: end.";
287}
288
289/**
290 * @tc.name: DfxAllocatorTest002
291 * @tc.desc: test dfxAllocator malloc and free
292 * @tc.type: FUNC
293 */
294HWTEST_F(LocalHandlerTest, DfxAllocatorTest002, TestSize.Level2)
295{
296    GTEST_LOG_(INFO) << "DfxAllocatorTest002: start.";
297    void* p = nullptr;
298    void* parr[MALLOC_TEST_TIMES] = {nullptr};
299    uint32_t size = MALLOC_TEST_SMALL_SIZE;
300    int res = 0;
301    DfxAllocator* allocator = GetDfxAllocator();
302    RegisterAllocator();
303    for (int i = 0; i < DFX_MEMPOOLS_NUM; i++) {
304        // malloc and free 1000 times
305        for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
306            p = malloc(size);
307            if (p == nullptr || !IsDfxAllocatorMem(p)) {
308                res = 1;
309            }
310            free(p);
311            if (allocator->dfxMempoolBuf[i].pageList != nullptr) {
312                res = 1;
313            }
314        }
315        // malloc 1000 times and free 1000 times
316        for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
317            parr[time] = malloc(size);
318            if (parr[time] == nullptr || !IsDfxAllocatorMem(parr[time])) {
319                res = 1;
320            }
321        }
322        for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
323            free(parr[time]);
324        }
325        if (allocator->dfxMempoolBuf[i].pageList != nullptr) {
326            res = 1;
327        }
328        size = size << 1;
329    }
330    UnregisterAllocator();
331    ASSERT_TRUE(res == 0);
332    GTEST_LOG_(INFO) << "DfxAllocatorTest002: end.";
333}
334
335/**
336 * @tc.name: DfxAllocatorTest003
337 * @tc.desc: test dfxAllocator mmap
338 * @tc.type: FUNC
339 */
340HWTEST_F(LocalHandlerTest, DfxAllocatorTest003, TestSize.Level2)
341{
342    GTEST_LOG_(INFO) << "DfxAllocatorTest003: start.";
343    void* p = nullptr;
344    void* parr[MALLOC_TEST_TIMES] = {nullptr};
345    uint32_t size = MALLOC_TEST_BIG_SIZE;
346    int res = 0;
347    DfxAllocator* allocator = GetDfxAllocator();
348    RegisterAllocator();
349    // malloc and free 1000 times
350    for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
351        p = malloc(size);
352        if (p == nullptr || !IsDfxAllocatorMem(p)) {
353            res = 1;
354        }
355        free(p);
356        if (allocator->pageList != nullptr) {
357            res = 1;
358        }
359    }
360    // malloc 1000 times and free 1000 times
361    for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
362        parr[time] = malloc(size);
363        if (parr[time] == nullptr || !IsDfxAllocatorMem(parr[time])) {
364            res = 1;
365        }
366    }
367    for (int time = 0; time < MALLOC_TEST_TIMES; time++) {
368        free(parr[time]);
369    }
370    if (allocator->pageList != nullptr) {
371        res = 1;
372    }
373    UnregisterAllocator();
374    ASSERT_TRUE(res == 0);
375    GTEST_LOG_(INFO) << "DfxAllocatorTest003: end.";
376}
377
378/**
379 * @tc.name: DfxAllocatorTest004
380 * @tc.desc: test dfxAllocator realloc
381 * @tc.type: FUNC
382 */
383HWTEST_F(LocalHandlerTest, DfxAllocatorTest004, TestSize.Level2)
384{
385    GTEST_LOG_(INFO) << "DfxAllocatorTest004: start.";
386    void* p = nullptr;
387    uint32_t size = MALLOC_TEST_SMALL_SIZE;
388    int res = 0;
389    DfxAllocator* allocator = GetDfxAllocator();
390    RegisterAllocator();
391    p = malloc(size);
392    (void)memset_s(p, size, 0, size);
393    size += MALLOC_TEST_SMALL_SIZE;
394    p = realloc(p, size);
395    if (p == nullptr || !IsDfxAllocatorMem(p)) {
396        res = 1;
397    }
398    if (allocator->dfxMempoolBuf[1].pageList == nullptr) {
399        res = 1;
400    }
401    free(p);
402    UnregisterAllocator();
403    ASSERT_TRUE(res == 0);
404    GTEST_LOG_(INFO) << "DfxAllocatorTest004: end.";
405}
406
407/**
408 * @tc.name: DfxAllocatorTest005
409 * @tc.desc: test dfxAllocator localhandler crash log
410 * @tc.type: FUNC
411 */
412HWTEST_F(LocalHandlerTest, DfxAllocatorTest005, TestSize.Level2)
413{
414    GTEST_LOG_(INFO) << "DfxAllocatorTest005: start.";
415    pid_t pid = fork();
416    if (pid < 0) {
417        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
418    } else if (pid == 0) {
419        DFX_InstallLocalSignalHandler();
420        sleep(1);
421        // alloc a buffer
422        int32_t initAllocSz = 10;
423        int32_t reallocSz = 20;
424        int8_t* addr = reinterpret_cast<int8_t*>(malloc(initAllocSz));
425        // overwrite the control block
426        int8_t* newAddr = addr - initAllocSz;
427        (void)memset_s(newAddr, initAllocSz, 0, initAllocSz);
428        addr = reinterpret_cast<int8_t*>(realloc(reinterpret_cast<void*>(addr), reallocSz));
429        free(addr);
430        // force crash if not crash in realloc
431        abort();
432    } else {
433        usleep(10000); // 10000 : sleep 10ms
434        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")";
435        sleep(2); // 2 : wait for cppcrash generating
436#ifdef __aarch64__
437        bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGABRT);
438#else
439        bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
440#endif
441        ASSERT_TRUE(ret);
442    }
443    GTEST_LOG_(INFO) << "DfxAllocatorTest005: end.";
444}
445
446/**
447 * @tc.name: DfxAllocatorTest006
448 * @tc.desc: test dfxAllocator localhandler abnormal scenario
449 * @tc.type: FUNC
450 */
451HWTEST_F(LocalHandlerTest, DfxAllocatorTest006, TestSize.Level2)
452{
453    GTEST_LOG_(INFO) << "DfxAllocatorTest005: start.";
454    int ret = IsDfxAllocatorMem(nullptr);
455    ASSERT_EQ(ret, 0);
456    GTEST_LOG_(INFO) << "DfxAllocatorTest005: end.";
457}
458} // namespace HiviewDFX
459} // namepsace OHOS
460