• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2022 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 #include <gtest/gtest.h>
16 #include <cinttypes>
17 #include <climits>
18 #include <cstdio>
19 #include <unistd.h>
20 #include <string>
21 #include <sys/time.h>
22 
23 #define SIZE_ALIGN (4 * sizeof(size_t))
24 #define THRESHOLD (0x1c00 * SIZE_ALIGN)
25 #define ITER_TIME 20
26 const int MALLOC_SIZE_ONE = 1024;
27 const int MALLOC_SIZE_TWO = 2048;
28 
handler(int s)29 static void handler(int s)
30 {
31 }
32 
33 using namespace testing::ext;
34 using namespace std;
35 
36 class MallocSafeUnlink : public testing::Test {
37 public:
38 
39     static void SetUpTestCase();
40     static void TearDownTestCase();
41     void SetUp();
42     void TearDown();
43 private:
44 };
45 
SetUp()46 void MallocSafeUnlink::SetUp()
47 {
48 }
TearDown()49 void MallocSafeUnlink::TearDown()
50 {
51 }
SetUpTestCase()52 void MallocSafeUnlink::SetUpTestCase()
53 {
54 }
TearDownTestCase()55 void MallocSafeUnlink::TearDownTestCase()
56 {
57 }
58 
59 volatile void *g_ptr;
60 
set_devide_chunk(int size)61 int set_devide_chunk(int size)
62 {
63     if (!(g_ptr = malloc(size))) {
64         printf("Malloc failed: %s\n", strerror(errno));
65         return -1;
66     }
67     return 0;
68 }
69 
child(void)70 static int child(void)
71 {
72     int *c;
73 	int *d;
74 
75     /* Set first dividing chunk */
76     if (set_devide_chunk(MALLOC_SIZE_TWO)) {
77         return -1;
78     }
79 
80     /*
81      * The init procedure makes the freelist unpredictable. To make sure trigger the safe-unlink
82      * check, Here we create as many chunks as possible to make sure there are enough chunks in
83      * bin[0] and malloc again. Basically this is heap spray.
84      */
85     for (int i = 0; i < 512; ++i) {
86 
87         c = (int *)malloc(MALLOC_SIZE_ONE);
88         if (!c) {
89             printf("Malloc failed: %s\n", strerror(errno));
90             return -1;
91         }
92         if (set_devide_chunk(MALLOC_SIZE_TWO)) {
93             return -1;
94         }
95         d = (int *)malloc(MALLOC_SIZE_ONE);
96         if (!d) {
97             printf("Malloc failed: %s\n", strerror(errno));
98             return -1;
99         }
100         if (set_devide_chunk(MALLOC_SIZE_TWO)) {
101             return -1;
102         }
103         free(d);
104         free(c);
105         /* exchange the prev and next pointer */
106         uintptr_t temp = c[0];
107         c[0] = c[1];
108         c[1] = temp;
109     }
110 
111     return 0;
112 }
113 
start_child(void)114 static pid_t start_child(void)
115 {
116     pid_t pid;
117     int ret;
118     pid = fork();
119     if (pid == 0) {
120         ret = child();
121         printf("child process normally out with %d\n", ret);
122         return ret;
123     }
124     return pid;
125 }
126 /*
127  * @tc.number CAM_FREE_FUN_0100
128  * @tc.name Apply part of the memory camfree reduction
129  * @tc.desc Test the basic features of CamFree
130 */
131 HWTEST_F(MallocSafeUnlink, safeUnlinkTest0100, Function | MediumTest | Level1)
132 {
133     sigset_t set;
134     int status;
135     pid_t pid;
136     int flag = 0;
137     struct timespec time1 = {5, 0};
138 
139     sigemptyset(&set);
140     sigaddset(&set, SIGCHLD);
141     sigprocmask(SIG_BLOCK, &set, 0);
142     signal(SIGCHLD, handler);
143 
144     pid = start_child();
145     if (pid == -1) {
146         printf("fork failed: %s\n", strerror(errno));
147     }
148     if (sigtimedwait(&set, 0, &time1) == -1) { /* Wait for 5 seconds */
149         if (errno == EAGAIN) {
150             flag = 1;
151         } else {
152             printf("sigtimedwait failed: %s\n", strerror(errno));
153         }
154         if (kill(pid, SIGKILL) == -1) {
155             printf("kill failed: %s\n", strerror(errno));
156         }
157     }
158 
159     if (waitpid(pid, &status, 0) != pid) {
160         printf("waitpid failed: %s\n", strerror(errno));
161     }
162 
163     if (flag) {
164         printf("Child process time out\n");
165     }
166 
167     if (WIFSIGNALED(status)) {
168         ASSERT_TRUE(WTERMSIG(status) == SIGSEGV || WTERMSIG(status) == SIGILL) << "child process out with %s\n" <<
169         WTERMSIG(status);
170     } else {
171         ASSERT_TRUE(false) << "child process finished normally\n";
172     }
173 }