1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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
36namespace {
37typedef char* (*DepthMallocSo)(int depth, int mallocSize);
38typedef void (*DepthFreeSo)(int depth, char *p);
39constexpr int MALLOC_SIZE = 1000;
40constexpr int ARGC_NUM_MAX = 3;
41constexpr int DOUBLE = 2;
42
43constexpr int USLEEP_TIME = 1000;
44// liba.z.so and libb.z.so for same so.
45#ifdef __arm__
46const std::vector<std::string> VEC_SO_PATH { "/system/lib/liba.z.so", "/system/lib/libb.z.so" };
47#else
48const std::vector<std::string> VEC_SO_PATH { "/system/lib64/liba.z.so", "/system/lib64/libb.z.so" };
49#endif
50unsigned int g_stickDepth = 1;
51}
52
53static 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
66static 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
84static 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
103static 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
134static 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
150static 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
167static 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
184static 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
202static 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
219static 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
238static 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
251static 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_IRGRP | S_IROTH);
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
288int 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