1 /*
2 * Copyright (c) 2021 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 <chrono>
16 #include <cstdio>
17 #include <cstdlib>
18 #include <string>
19 #include <vector>
20 #include <dlfcn.h>
21 #include <fcntl.h>
22 #include <memory.h>
23 #include <pthread.h>
24 #include <unistd.h>
25 #include <sys/mman.h>
26 #include <sys/prctl.h>
27 #include <sys/stat.h>
28 #include <sys/syscall.h>
29 #include <sys/types.h>
30
31 #include "memory_trace.h"
32 #include "securec.h"
33
34 #pragma clang optimize off
35
36 namespace {
37 typedef char* (*DepthMallocSo)(int depth, int mallocSize);
38 typedef void (*DepthFreeSo)(int depth, char *p);
39 constexpr int MALLOC_SIZE = 1000;
40 constexpr int ARGC_NUM_MAX = 3;
41 constexpr int DOUBLE = 2;
42
43 constexpr int USLEEP_TIME = 1000;
44 // liba.z.so and libb.z.so for same so.
45 #ifdef __arm__
46 const std::vector<std::string> VEC_SO_PATH { "/system/lib/liba.z.so", "/system/lib/libb.z.so" };
47 #else
48 const std::vector<std::string> VEC_SO_PATH { "/system/lib64/liba.z.so", "/system/lib64/libb.z.so" };
49 #endif
50 unsigned int g_stickDepth = 1;
51 }
52
CallocFun()53 static void CallocFun()
54 {
55 static int i = 0;
56 char* ptr = static_cast<char*>(calloc(1, MALLOC_SIZE / 100));
57 if (ptr == nullptr) {
58 fprintf(stderr, "calloc err.\n");
59 return;
60 }
61 fprintf(stderr, "calloc i=%d\n", i);
62 free(ptr);
63 i++;
64 }
65
ReallocFun()66 static void ReallocFun()
67 {
68 static int i = 0;
69 char* ptr = static_cast<char*>(calloc(1, MALLOC_SIZE / 10)); // 10: multiple num
70 if (ptr == nullptr) {
71 fprintf(stderr, "calloc err.\n");
72 return;
73 }
74 ptr = static_cast<char*>(realloc(ptr, MALLOC_SIZE * 10)); // 10: multiple num
75 if (ptr == nullptr) {
76 fprintf(stderr, "realloc err.\n");
77 return;
78 }
79 fprintf(stderr, "realloc i=%d\n", i);
80 free(ptr);
81 i++;
82 }
83
DepthMallocFree(int depth=0,int mallocSize=100)84 static bool DepthMallocFree(int depth = 0, int mallocSize = 100)
85 {
86 if (depth < 0 || mallocSize <= 0) {
87 return false;
88 }
89 if (depth == 0) {
90 char* ptr = static_cast<char*>(malloc(mallocSize));
91 if (ptr == nullptr) {
92 fprintf(stderr, "malloc err.\n");
93 return false;
94 }
95 fprintf(stderr, "%s\n", __func__);
96 *ptr = 'a';
97 free(ptr);
98 return true;
99 }
100 return (DepthMallocFree(depth - 1, mallocSize));
101 }
102
DlopenAndCloseSo(const std::string & filePath,int size)103 static void DlopenAndCloseSo(const std::string& filePath, int size)
104 {
105 void* handle = nullptr;
106 DepthMallocSo mallocFunc = nullptr;
107 DepthFreeSo freeFunc = nullptr;
108
109 fprintf(stderr, "dlopen %s %d!!!\n", filePath.data(), size);
110 usleep(USLEEP_TIME * 300); // 300 ms
111 handle = dlopen(filePath.data(), RTLD_LAZY);
112 if (handle == nullptr) {
113 fprintf(stderr, "library not exist!\n");
114 exit(0);
115 }
116 mallocFunc = (DepthMallocSo)dlsym(handle, "DepthMallocSo");
117 freeFunc = (DepthFreeSo)dlsym(handle, "DepthFreeSo");
118 if (mallocFunc == nullptr || freeFunc == nullptr) {
119 fprintf(stderr, "function not exist!\n");
120 exit(0);
121 }
122 char* ptr = nullptr;
123 for (size_t i = 0; i < 20; i++) { // 20: loop count
124 ptr = mallocFunc(g_stickDepth, size);
125 *ptr = 'a';
126 freeFunc(g_stickDepth, ptr);
127 }
128 if (handle != nullptr) {
129 usleep(USLEEP_TIME * 300); // 300 ms
130 dlclose(handle);
131 }
132 }
133
MmapAndMunMap()134 static int MmapAndMunMap()
135 {
136 size_t size = (1024);
137
138 char* ptr = static_cast<char*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
139 if (ptr == MAP_FAILED) {
140 fprintf(stderr, "Mmap err.\n");
141 ptr = nullptr;
142 return 1;
143 }
144
145 (void)memset_s(ptr, size, 0, size);
146 munmap(ptr, size);
147 return 0;
148 }
149
Fun1()150 static void Fun1()
151 {
152 static int i = 0;
153 char* ptr = static_cast<char*>(malloc(MALLOC_SIZE));
154 if (ptr == nullptr) {
155 fprintf(stderr, "malloc err.\n");
156 return;
157 }
158 fprintf(stderr, "i=%d\n", i);
159 *ptr = 'a';
160 free(ptr);
161 i++;
162 MmapAndMunMap();
163 CallocFun();
164 ReallocFun();
165 }
166
Fun2()167 static void Fun2()
168 {
169 Fun1();
170 static int i = 0;
171 char *ptr = static_cast<char*>(malloc(MALLOC_SIZE));
172 if (ptr == nullptr) {
173 fprintf(stderr, "malloc err.\n");
174 return;
175 }
176 fprintf(stderr, "i=%d\n", i);
177 *ptr = 'a';
178 if (i % DOUBLE == 0) {
179 free(ptr);
180 }
181 i++;
182 }
183
Fun3()184 static void Fun3()
185 {
186 Fun2();
187 static int i = 0;
188 char *ptr = static_cast<char*>(malloc(MALLOC_SIZE));
189 if (ptr == nullptr) {
190 fprintf(stderr, "malloc err.\n");
191 return;
192 }
193 fprintf(stderr, "i=%d\n", i);
194 *ptr = 'a';
195 if (i % DOUBLE == 0) {
196 free(ptr);
197 }
198 i++;
199 DlopenAndCloseSo(VEC_SO_PATH[0], MALLOC_SIZE * DOUBLE);
200 }
201
Fun4()202 static void Fun4()
203 {
204 Fun3();
205 static int i = 0;
206 char *ptr = static_cast<char*>(malloc(MALLOC_SIZE));
207 if (ptr == nullptr) {
208 fprintf(stderr, "malloc err.\n");
209 return;
210 }
211 fprintf(stderr, "i=%d\n", i);
212 *ptr = 'a';
213 if (i % DOUBLE == 0) {
214 free(ptr);
215 }
216 i++;
217 }
218
Fun5()219 static void Fun5()
220 {
221 Fun4();
222 static int i = 0;
223 char *ptr = static_cast<char*>(malloc(MALLOC_SIZE));
224 if (ptr == nullptr) {
225 fprintf(stderr, "malloc err.\n");
226 return;
227 }
228 fprintf(stderr, "i=%d\n", i);
229 *ptr = 'a';
230 if (i % DOUBLE == 0) {
231 free(ptr);
232 }
233 i++;
234 DepthMallocFree(g_stickDepth * 30); // 30: depth count
235 DlopenAndCloseSo(VEC_SO_PATH[1], MALLOC_SIZE * 3); // 3: multiple num
236 }
237
HhreadFuncCpp(void * param)238 static void* HhreadFuncCpp(void* param)
239 {
240 std::string name = "thread";
241 name = name + std::to_string(gettid());
242 prctl(PR_SET_NAME, name.c_str());
243 int forNum = *static_cast<int*>(param);
244 for (int num = 0; num < forNum; num++) {
245 fprintf(stderr, "thread %d:num=%d\n", gettid(), num);
246 Fun5();
247 }
248 return nullptr;
249 }
250
TestMemoryMap()251 static void TestMemoryMap()
252 {
253 constexpr int smallSize = 4096;
254 constexpr int bigSize = 8192;
255 int fd = open("/bin/hiebpf", O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
256 if (fd < 0) {
257 printf("open %s failed\n", "/bin/hiebpf");
258 return;
259 }
260
261 void* mapAddr1 = mmap(nullptr, smallSize, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_POPULATE, fd, 0);
262 if (mapAddr1 == MAP_FAILED) {
263 printf("named mmap failed\n");
264 close(fd);
265 return;
266 }
267 printf("named mmap size: 4096, fd: %d\n", fd);
268
269 void* mapAddr2 = mmap(nullptr, bigSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
270 if (mapAddr2 == MAP_FAILED) {
271 printf("anonymous mmap failed\n");
272 close(fd);
273 munmap(mapAddr1, smallSize);
274 return;
275 }
276 printf("anonymous mmap size: 8192\n");
277
278 memtrace(reinterpret_cast<void*>(0x123456), 3333, "memtrace_test", true); // 3333 num
279 printf("memtrace(0x123456, 3333, \"memtrace_test\", true)\n");
280
281 memtrace(reinterpret_cast<void*>(0x123456), 3333, "memtrace_test", false); // 3333 num
282 printf("memtrace(0x123456, 3333, \"memtrace_test\", false)\n");
283 close(fd);
284 munmap(mapAddr1, smallSize);
285 munmap(mapAddr2, bigSize);
286 }
287
main(int argc,char * argv[])288 int main(int argc, char *argv[])
289 {
290 int threadNum = 1;
291 int forNum = 10;
292 if (argc == ARGC_NUM_MAX) {
293 if (atoi(argv[1]) > 0 && atoi(argv[1]) <= 10) { // 10: max threads
294 threadNum = atoi(argv[1]);
295 }
296 if (atoi(argv[2]) > 0 && atoi(argv[2]) <= 100) { // 2: args num. 100: max value
297 forNum = atoi(argv[2]); // 2: args num
298 }
299 } else if (argc > ARGC_NUM_MAX) {
300 printf("command error, argc must <= %d\n", ARGC_NUM_MAX);
301 return 0;
302 }
303 fprintf(stderr, "start.Enter or send signal for next.\n");
304 getchar();
305 TestMemoryMap();
306
307 fprintf(stderr, "forNum = %d, threadNum = %d\n", forNum, threadNum);
308 fprintf(stderr, "Notice: need copy libnativetest_so.z.so for %s, %s\n",
309 VEC_SO_PATH[0].data(), VEC_SO_PATH[1].data());
310 pthread_t* thrArray = new (std::nothrow) pthread_t[threadNum];
311 if (!thrArray) {
312 printf("new thread array failed.\n");
313 return 1;
314 }
315 int idx;
316 for (idx = 0; idx < threadNum; ++idx) {
317 if (pthread_create(thrArray + idx, nullptr, HhreadFuncCpp, static_cast<void*>(&forNum)) != 0) {
318 printf("Creating thread failed.\n");
319 }
320 }
321 for (idx = 0; idx < threadNum; ++idx) {
322 pthread_join(thrArray[idx], nullptr);
323 }
324 delete []thrArray;
325
326 fprintf(stderr, "end.\n");
327 return 0;
328 }
329
330 #pragma clang optimize on