1e41f4b71Sopenharmony_ci# User-Mode Memory Debugging
2e41f4b71Sopenharmony_ci## Basic Concepts
3e41f4b71Sopenharmony_ci
4e41f4b71Sopenharmony_ciThe musl libc library of the debug version provides mechanisms, such as memory leak check, heap memory statistics, memory corruption check, and backtrace, to improve the efficiency in locating memory problems in user space.
5e41f4b71Sopenharmony_ci
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciInstrumentation is performed in the **malloc** and **free** APIs to log key node information. The memory node integrity is checked when memory is requested and released by an application. When the application ends, memory statistics are provided to help identifying memory leaks.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci## Working Principles
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci
12e41f4b71Sopenharmony_ci### Memory Leak Check
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ciThe memory debugging module maintains 128 (that is the maximum number of threads supported in the system) linked lists for each process. The index of each linked list is the thread ID.
15e41f4b71Sopenharmony_ci
16e41f4b71Sopenharmony_ciWhen memory is requested, key information is saved to the memory node control block, which is inserted to the corresponding linked list based on the thread ID.
17e41f4b71Sopenharmony_ci
18e41f4b71Sopenharmony_ciWhen memory is released, the system matches the memory node control block based on the memory address to be released and deletes the control block.
19e41f4b71Sopenharmony_ci
20e41f4b71Sopenharmony_ci**Figure 1** Heap memory node linked list
21e41f4b71Sopenharmony_ci
22e41f4b71Sopenharmony_ci![](figures/heap-memory-node-linked-list.png "heap-memory-node-linked-list")
23e41f4b71Sopenharmony_ci
24e41f4b71Sopenharmony_ciWhen memory is allocated, the returned address is saved in a link register (LR). During the process running, the system adds information, such as the LR corresponding to the suspected leak, to the memory node control block. The following figure shows the heap memory node information.
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci**Figure 2** Heap memory node information
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci![](figures/heap-memory-node-information.png "heap-memory-node-information")
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci**TID** indicates the thread ID; **PID** indicates the process ID; **ptr** indicates the address of the memory requested; **size** indicates the size of the requested memory; **lr[*n*]** indicates the address of the call stack, and *n* is configurable.
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ciWhen memory is released, the input parameter pointer in the **free** API is used to match the **ptr** field of the memory node. If the pointer is the same as the **ptr** field of the memory node, the memory node control block will be deleted.
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ciYou can export the memory debugging information of each process through the serial port or file, and use the addr2line tool to convert the exported information into the code lines that cause memory leaks. In this way, the memory leakage problem can be solved.
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ci**Figure 3** Process of locating the code line for a memory leak
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ci![](figures/process-of-locating-the-code-lines-for-a-memory-leak.png "process-of-locating-the-code-lines-for-a-memory-leak")
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ci### Heap Memory Statistics
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ciYou can collect statistics on the percentage of heap memory requested by each thread to provide data support for optimizing memory usage of user programs. The **malloc** and **free** APIs are involved in user-mode heap memory statistics. As shown in the figure above, each process maintains 128 linked lists, and the index of each linked list is a thread ID. When heap memory is requested, the **ptr** and **size** information is recorded in the memory node control block, which is inserted to a linked list with the thread ID as the header. When the heap memory is released, the corresponding heap memory block is removed from the linked list based on the **ptr**. In addition, the system calculates the total heap memory used by the current thread and updates its heap memory usage and peak heap memory usage.
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ci
46e41f4b71Sopenharmony_ci### Memory Integrity Check
47e41f4b71Sopenharmony_ci
48e41f4b71Sopenharmony_ci- Requested memory less than or equal to 0x1c000 bytes
49e41f4b71Sopenharmony_ci  
50e41f4b71Sopenharmony_ci  When the requested memory is less than or equal to 0x1c000 bytes, **malloc** uses the heap allocation algorithm to allocate memory.
51e41f4b71Sopenharmony_ci  
52e41f4b71Sopenharmony_ci  When a user program requests heap memory, information such as the check value is added to the heap memory node. If the check value is abnormal, it is probably that the previous heap memory block is overwritten. Currently, the scenario where the check value is damaged by a wild pointer cannot be identified. When memory is allocated or released, the memory node check value is verified. If the memory node is corrupted and the verification fails, the following information is output: TID, PID, and call stack information saved when the previous heap memory block of the corrupted node is allocated. You can use the addr2line tool to obtain the specific code line and rectify the fault.
53e41f4b71Sopenharmony_ci  
54e41f4b71Sopenharmony_ci  **Figure 4** Adding a check value to the node header information
55e41f4b71Sopenharmony_ci  
56e41f4b71Sopenharmony_ci  ![](figures/adding-a-check-value-to-the-node-header-information.png "adding-a-check-value-to-the-node-header-information")
57e41f4b71Sopenharmony_ci  
58e41f4b71Sopenharmony_ci  When heap memory is released by **free**, the memory block is not released immediately. Instead, the magic number 0xFE is written into the memory block, which is then placed in the free queue to prevent the memory block from being allocated by **malloc** within a certain period of time. When a wild pointer or **use-after-free** operation is performed to read the memory, an exception can be detected. However, this mechanism does not apply to write operations.
59e41f4b71Sopenharmony_ci  
60e41f4b71Sopenharmony_ci  **Figure 5** Process of releasing memory
61e41f4b71Sopenharmony_ci  
62e41f4b71Sopenharmony_ci  ![](figures/process-of-releasing-memory.png "process-of-releasing-memory")
63e41f4b71Sopenharmony_ci  
64e41f4b71Sopenharmony_ci  
65e41f4b71Sopenharmony_ci  
66e41f4b71Sopenharmony_ci- Requested memory greater than 0x1c000 bytes
67e41f4b71Sopenharmony_ci
68e41f4b71Sopenharmony_ci  When the requested memory is greater than 0x1c000 bytes, **malloc** uses **mmap** to allocate memory.
69e41f4b71Sopenharmony_ci
70e41f4b71Sopenharmony_ci  When **mmap** is used to allocate a large memory block, one more page is allocated at the start and end of the memory region. The current **PAGE_SIZE** of each page is **0x1000**. The permissions of the two pages are set to **PROT_NONE** (no read or write permission) by using the **mprotect** API to prevent out-of-bounds read and write of memory. If out-of-bounds read and write of memory occurs, the user program becomes abnormal because the user does not have the read or write permission. The code logic can be identified based on the abnormal call stack information.
71e41f4b71Sopenharmony_ci
72e41f4b71Sopenharmony_ci  **Figure 6** Layout of the memory allocated by using the **mmap** mechanism of **malloc**
73e41f4b71Sopenharmony_ci
74e41f4b71Sopenharmony_ci  ![](figures/layout-of-the-memory-allocated-by-using-the-mmap-mechanism-of-malloc.png "layout-of-the-memory-allocated-by-using-the-mmap-mechanism-of-malloc")
75e41f4b71Sopenharmony_ci
76e41f4b71Sopenharmony_ci### Usage Guide
77e41f4b71Sopenharmony_ci#### Available APIs
78e41f4b71Sopenharmony_ci
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ci  **Table 1** Memory debugging APIs
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ci| API| Description|
83e41f4b71Sopenharmony_ci| -------- | -------- |
84e41f4b71Sopenharmony_ci| mem_check_init | Initializes the memory check module.|
85e41f4b71Sopenharmony_ci| watch_mem | Obtains the thread-level heap memory usage.|
86e41f4b71Sopenharmony_ci| check_leak | Checks for heap memory leaks.|
87e41f4b71Sopenharmony_ci| check_heap_integrity | Checks the heap memory integrity.|
88e41f4b71Sopenharmony_ci| backtrace | Obtains the address information of the call stack.|
89e41f4b71Sopenharmony_ci| backtrace_symbols | Obtains symbol information based on address information.|
90e41f4b71Sopenharmony_ci| print_trace | Prints call stack information.|
91e41f4b71Sopenharmony_ci
92e41f4b71Sopenharmony_ci
93e41f4b71Sopenharmony_ci  **Table 2** Call stack backtracking APIs
94e41f4b71Sopenharmony_ci
95e41f4b71Sopenharmony_ci| API| Description|
96e41f4b71Sopenharmony_ci| -------- | -------- |
97e41f4b71Sopenharmony_ci| backtrace | Obtains the address information of the call stack.|
98e41f4b71Sopenharmony_ci| backtrace_symbols | Obtains symbol information based on address information.|
99e41f4b71Sopenharmony_ci| print_trace | Prints call stack information.|
100e41f4b71Sopenharmony_ci
101e41f4b71Sopenharmony_ci### How to Use
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ci
104e41f4b71Sopenharmony_ciBy default, the OpenHarmony debug version is compiled when a project is built. The libc library of the debug version has integrated the APIs for memory debugging. You can enable memory debugging as required.
105e41f4b71Sopenharmony_ci
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ciYou can perform heap memory debugging by using either of the following:
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci
110e41f4b71Sopenharmony_ci- API: By calling APIs, you can accurately check the heap memory information of a specific code logic segment. However, you have to modify user code.
111e41f4b71Sopenharmony_ci
112e41f4b71Sopenharmony_ci- CLI: By using the CLI, you do not need to modify user code. However, you cannot accurately check the heap memory information of a specific logic segment.
113e41f4b71Sopenharmony_ci
114e41f4b71Sopenharmony_ci
115e41f4b71Sopenharmony_ci> **NOTE**<br>
116e41f4b71Sopenharmony_ci> After memory debugging is enabled, a heap memory leak check and a heap memory integrity check will be performed by default when a process exits. If memory debugging is disabled, the heap memory statistics, heap memory leak check, and heap memory integrity check cannot be enabled, and there is no response to the calling of any debug API.
117e41f4b71Sopenharmony_ci
118e41f4b71Sopenharmony_ci
119e41f4b71Sopenharmony_ci
120e41f4b71Sopenharmony_ci
121e41f4b71Sopenharmony_ci#### Calling APIs
122e41f4b71Sopenharmony_ci
123e41f4b71Sopenharmony_ci
124e41f4b71Sopenharmony_ci##### Sample Code
125e41f4b71Sopenharmony_ci
126e41f4b71Sopenharmony_ciThe sample code explicitly calls the related APIs of the memory debugging module to check the memory.
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_ci
129e41f4b71Sopenharmony_ci```c
130e41f4b71Sopenharmony_ci#include <pthread.h>
131e41f4b71Sopenharmony_ci#include <stdlib.h>
132e41f4b71Sopenharmony_ci#include <stdio.h>
133e41f4b71Sopenharmony_ci#include <debug.h> // Header file that includes the declaration of the memory debugging APIs
134e41f4b71Sopenharmony_ci
135e41f4b71Sopenharmony_ci#define MALLOC_LEAK_SIZE  0x300
136e41f4b71Sopenharmony_ci
137e41f4b71Sopenharmony_civoid func(void)
138e41f4b71Sopenharmony_ci{
139e41f4b71Sopenharmony_ci    char *ptr = malloc(MALLOC_LEAK_SIZE);
140e41f4b71Sopenharmony_ci    memset(ptr, '3', MALLOC_LEAK_SIZE);
141e41f4b71Sopenharmony_ci}
142e41f4b71Sopenharmony_ci
143e41f4b71Sopenharmony_ciint main()
144e41f4b71Sopenharmony_ci{
145e41f4b71Sopenharmony_ci    mem_check_init(NULL); // Output the memory debugging information through the serial port. This function must be called before the user program requests the heap memory for the first time (generally called at the entry of the main function). Otherwise, the debugging information is inaccurate.
146e41f4b71Sopenharmony_ci    // mem_check_init("/storage/mem_debug.txt"); // Output the memory debugging information to the /storage/mem_debug.txt file. If the file fails to be created, output the information through the serial port.
147e41f4b71Sopenharmony_ci    char *ptr = malloc(MALLOC_LEAK_SIZE);
148e41f4b71Sopenharmony_ci    memset(ptr, '1', MALLOC_LEAK_SIZE);
149e41f4b71Sopenharmony_ci
150e41f4b71Sopenharmony_ci    watch_mem(); // Obtain the thread-level memory statistics in the current code.
151e41f4b71Sopenharmony_ci    func();
152e41f4b71Sopenharmony_ci    check_heap_integrity(); // Check the integrity of the heap memory nodes.
153e41f4b71Sopenharmony_ci    check_leak(); // Check whether a heap memory leak occurs in the current code. (Generally, the check result is accurate before the application exits. If the check is performed after the calling of malloc and before the calling of free, the result is inaccurate.)
154e41f4b71Sopenharmony_ci    return 0;
155e41f4b71Sopenharmony_ci}
156e41f4b71Sopenharmony_ci```
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci
159e41f4b71Sopenharmony_ci##### Compilation
160e41f4b71Sopenharmony_ci
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_ci```
163e41f4b71Sopenharmony_ci$ clang -o mem_check mem_check.c -funwind-tables -rdynamic -g -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos --sysroot=/home/<user-name>/directory/out/hispark_taurus/ipcamera_hispark_taurus/sysroot $(clang -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos -print-file-name=libunwind.a)
164e41f4b71Sopenharmony_ci```
165e41f4b71Sopenharmony_ci
166e41f4b71Sopenharmony_ci
167e41f4b71Sopenharmony_ci> **NOTE**
168e41f4b71Sopenharmony_ci>
169e41f4b71Sopenharmony_ci> - In this example, the compiler path is written into an environment variable in the **.bashrc** file.
170e41f4b71Sopenharmony_ci>
171e41f4b71Sopenharmony_ci> - When compiling user programs and required libraries, add the option **-funwind-tables -rdynamic -g** for stack backtracking.
172e41f4b71Sopenharmony_ci>
173e41f4b71Sopenharmony_ci> - The **-mfloat-abi=softfp**, **-mcpu=cortex-a7**, and **-mfpu=neon-vfpv4** options specify the floating-point calculation optimization, chip architecture, and FPU, which must be the same as the compilation options used by the libc library. Otherwise, the libc library file cannot be found during the link time.
174e41f4b71Sopenharmony_ci>
175e41f4b71Sopenharmony_ci> - **-target arm-liteos** specifies the path of the library files related to the compiler.
176e41f4b71Sopenharmony_ci>
177e41f4b71Sopenharmony_ci> - **--sysroot=/home/<user-name>/harmony/out/hispark_taurus/ipcamera_hispark_taurus/sysroot** specifies the root directory of the compiler library files. In this example, the OpenHarmony project code is stored in **/home/<user-name>/harmony**. The **out/hispark_taurus/ipcamera_hispark_taurus** directory indicates the product specified by the **hb set** command during compilation. In this example, **ipcamera_hispark_taurus** is the product specified.
178e41f4b71Sopenharmony_ci>
179e41f4b71Sopenharmony_ci> - **$(clang -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos -print-file-name=libunwind.a)** specifies the path of the unwind library.
180e41f4b71Sopenharmony_ci
181e41f4b71Sopenharmony_ci
182e41f4b71Sopenharmony_ci##### Debugging Information
183e41f4b71Sopenharmony_ci
184e41f4b71Sopenharmony_ci
185e41f4b71Sopenharmony_ci```
186e41f4b71Sopenharmony_ciOHOS # ./mem_check
187e41f4b71Sopenharmony_ciOHOS #
188e41f4b71Sopenharmony_ci==PID:4== Heap memory statistics(bytes): // Heap memory statistics
189e41f4b71Sopenharmony_ci    [Check point]: // Call stack of the check point
190e41f4b71Sopenharmony_ci        #00: <main+0x38>[0x86c] -> mem_check
191e41f4b71Sopenharmony_ci        #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
192e41f4b71Sopenharmony_ci
193e41f4b71Sopenharmony_ci    [TID: 18, Used: 0x320] // The heap memory is occupied by thread No. 18. The current process has only one thread.
194e41f4b71Sopenharmony_ci
195e41f4b71Sopenharmony_ci==PID:4== Total heap: 0x320 byte(s), Peak: 0x320 byte(s)
196e41f4b71Sopenharmony_ci
197e41f4b71Sopenharmony_ciCheck heap integrity ok! // Heap memory integrity check
198e41f4b71Sopenharmony_ci
199e41f4b71Sopenharmony_ci==PID:4== Detected memory leak(s): // Memory leak information and call stack
200e41f4b71Sopenharmony_ci    [Check point]:
201e41f4b71Sopenharmony_ci        #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
202e41f4b71Sopenharmony_ci        #01: <main+0x44>[0x878] -> mem_check
203e41f4b71Sopenharmony_ci
204e41f4b71Sopenharmony_ci    [TID:18 Leak:0x320 byte(s)] Allocated from:
205e41f4b71Sopenharmony_ci        #00: <main+0x1c>[0x850] -> mem_check
206e41f4b71Sopenharmony_ci        #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
207e41f4b71Sopenharmony_ci
208e41f4b71Sopenharmony_ci    [TID:18 Leak:0x320 byte(s)] Allocated from:
209e41f4b71Sopenharmony_ci        #00: <func+0x14>[0x810] -> mem_check
210e41f4b71Sopenharmony_ci        #01: <main+0x3c>[0x870] -> mem_check
211e41f4b71Sopenharmony_ci        #02: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
212e41f4b71Sopenharmony_ci
213e41f4b71Sopenharmony_ci==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
214e41f4b71Sopenharmony_ci
215e41f4b71Sopenharmony_ci==PID:4== Detected memory leak(s):
216e41f4b71Sopenharmony_ci    [Check point]:
217e41f4b71Sopenharmony_ci        #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
218e41f4b71Sopenharmony_ci        #01: <exit+0x28>[0x111ec] -> /lib/libc.so
219e41f4b71Sopenharmony_ci
220e41f4b71Sopenharmony_ci    [TID:18 Leak:0x320 byte(s)] Allocated from:
221e41f4b71Sopenharmony_ci        #00: <main+0x1c>[0x850] -> mem_check
222e41f4b71Sopenharmony_ci        #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_ci    [TID:18 Leak:0x320 byte(s)] Allocated from:
225e41f4b71Sopenharmony_ci        #00: <func+0x14>[0x810] -> mem_check
226e41f4b71Sopenharmony_ci        #01: <main+0x3c>[0x870] -> mem_check
227e41f4b71Sopenharmony_ci        #02: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
228e41f4b71Sopenharmony_ci
229e41f4b71Sopenharmony_ci==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
230e41f4b71Sopenharmony_ci
231e41f4b71Sopenharmony_ciCheck heap integrity ok!
232e41f4b71Sopenharmony_ci```
233e41f4b71Sopenharmony_ci
234e41f4b71Sopenharmony_ci
235e41f4b71Sopenharmony_ci##### Call Stack Parsing
236e41f4b71Sopenharmony_ci
237e41f4b71Sopenharmony_ciThe **parse_mem_info.sh** script in **kernel/liteos_a/tools/scripts/parse_memory/** can be used to parse the call stack. You can use the script to convert the debug information into specific source code line number. In the following command, **mem_debug.txt** stores the memory debugging information, and **elf1** and **elf2** are the executable and linkable format (ELF) files to parse.
238e41f4b71Sopenharmony_ci
239e41f4b71Sopenharmony_ci
240e41f4b71Sopenharmony_ci```
241e41f4b71Sopenharmony_ci$ ./parse_mem_info.sh mem_debug.txt elf1 elf2 elf3 ...
242e41f4b71Sopenharmony_ci```
243e41f4b71Sopenharmony_ci
244e41f4b71Sopenharmony_ciExample:
245e41f4b71Sopenharmony_ci
246e41f4b71Sopenharmony_ci
247e41f4b71Sopenharmony_ci```
248e41f4b71Sopenharmony_ci$ ./parse_mem_info.sh mem_debug.txt mem_check
249e41f4b71Sopenharmony_ciCompiler is [gcc/llvm]: llvm
250e41f4b71Sopenharmony_ciNow using addr2line ...
251e41f4b71Sopenharmony_ci
252e41f4b71Sopenharmony_ci==PID:4== Heap memory statistics(bytes):
253e41f4b71Sopenharmony_ci    [Check point]:
254e41f4b71Sopenharmony_ci        #00: <main+0x38>[0x86c] at /usr1/xxx/TEST_ELF/mem_check.c:22
255e41f4b71Sopenharmony_ci        #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
256e41f4b71Sopenharmony_ci
257e41f4b71Sopenharmony_ci    [TID: 18, Used: 0x320]
258e41f4b71Sopenharmony_ci
259e41f4b71Sopenharmony_ci==PID:4== Total heap: 0x320 byte(s), Peak: 0x320 byte(s)
260e41f4b71Sopenharmony_ci
261e41f4b71Sopenharmony_ciCheck heap integrity ok!
262e41f4b71Sopenharmony_ci
263e41f4b71Sopenharmony_ci==PID:4== Detected memory leak(s):
264e41f4b71Sopenharmony_ci    [Check point]:
265e41f4b71Sopenharmony_ci        #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
266e41f4b71Sopenharmony_ci        #01: <main+0x44>[0x878] at /usr1/xxx/TEST_ELF/mem_check.c:28
267e41f4b71Sopenharmony_ci
268e41f4b71Sopenharmony_ci    [TID:18 Leak:0x320 byte(s)] Allocated from:
269e41f4b71Sopenharmony_ci        #00: <main+0x1c>[0x850] at /usr1/xxx/TEST_ELF/mem_check.c:17
270e41f4b71Sopenharmony_ci        #01: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
271e41f4b71Sopenharmony_ci
272e41f4b71Sopenharmony_ci    [TID:18 Leak:0x320 byte(s)] Allocated from:
273e41f4b71Sopenharmony_ci        #00: <func+0x14>[0x810] at /usr1/xxx/TEST_ELF/mem_check.c:9
274e41f4b71Sopenharmony_ci        #01: <main+0x3c>[0x870] at /usr1/xxx/TEST_ELF/mem_check.c:24
275e41f4b71Sopenharmony_ci        #02: <(null)+0x24baf9dc>[0x219dc] -> /lib/libc.so
276e41f4b71Sopenharmony_ci
277e41f4b71Sopenharmony_ci==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
278e41f4b71Sopenharmony_ci```
279e41f4b71Sopenharmony_ci
280e41f4b71Sopenharmony_ci#### Using the CLI
281e41f4b71Sopenharmony_ci
282e41f4b71Sopenharmony_ci
283e41f4b71Sopenharmony_ciIn addition to calling APIs to check the memory used by user-mode processes, you can run CLI commands to collect memory statistics, check for memory leaks, and check memory integrity.
284e41f4b71Sopenharmony_ci
285e41f4b71Sopenharmony_ci```
286e41f4b71Sopenharmony_ci--mwatch: initializes memory debugging, registers signals, and outputs memory debugging information through the serial port.
287e41f4b71Sopenharmony_ci--mrecord <f_path>: initializes memory debugging, registers signals, and saves the memory debugging information to the f_path file. If the f_path file fails to be created, output the memory debugging information through the serial port.
288e41f4b71Sopenharmony_ci```
289e41f4b71Sopenharmony_ci
290e41f4b71Sopenharmony_ci
291e41f4b71Sopenharmony_ciIf the process to debug does not exit, you can use the signal mechanism to obtain the corresponding information:
292e41f4b71Sopenharmony_ci
293e41f4b71Sopenharmony_ci```
294e41f4b71Sopenharmony_cikill -35 <pid> # Check the thread-level heap memory usage.
295e41f4b71Sopenharmony_cikill -36 <pid> # Check for heap memory leaks.
296e41f4b71Sopenharmony_cikill -37 <pid> # Check whether the head node of the heap memory is complete.
297e41f4b71Sopenharmony_ci```
298e41f4b71Sopenharmony_ci
299e41f4b71Sopenharmony_ci
300e41f4b71Sopenharmony_ci##### Sample Code
301e41f4b71Sopenharmony_ci
302e41f4b71Sopenharmony_ciThe sample code constructs a memory problem and uses the command line to perform memory debugging.
303e41f4b71Sopenharmony_ci
304e41f4b71Sopenharmony_ci
305e41f4b71Sopenharmony_ci```c
306e41f4b71Sopenharmony_ci#include <pthread.h>
307e41f4b71Sopenharmony_ci#include <stdlib.h>
308e41f4b71Sopenharmony_ci#include <stdio.h>
309e41f4b71Sopenharmony_ci
310e41f4b71Sopenharmony_ci#define MALLOC_LEAK_SIZE  0x300
311e41f4b71Sopenharmony_ci
312e41f4b71Sopenharmony_civoid func(void)
313e41f4b71Sopenharmony_ci{
314e41f4b71Sopenharmony_ci    char *ptr = malloc(MALLOC_LEAK_SIZE);
315e41f4b71Sopenharmony_ci    memset(ptr, '3', MALLOC_LEAK_SIZE);
316e41f4b71Sopenharmony_ci}
317e41f4b71Sopenharmony_ci
318e41f4b71Sopenharmony_ciint main()
319e41f4b71Sopenharmony_ci{
320e41f4b71Sopenharmony_ci    char *ptr = malloc(MALLOC_LEAK_SIZE);
321e41f4b71Sopenharmony_ci    memset(ptr, '1', MALLOC_LEAK_SIZE);
322e41f4b71Sopenharmony_ci    func();
323e41f4b71Sopenharmony_ci    while (1);
324e41f4b71Sopenharmony_ci}
325e41f4b71Sopenharmony_ci```
326e41f4b71Sopenharmony_ci
327e41f4b71Sopenharmony_ci
328e41f4b71Sopenharmony_ci##### Compilation
329e41f4b71Sopenharmony_ci
330e41f4b71Sopenharmony_ciFor details, see [Compilation](#compilation).
331e41f4b71Sopenharmony_ci
332e41f4b71Sopenharmony_ci
333e41f4b71Sopenharmony_ci##### Running the mwatch Command
334e41f4b71Sopenharmony_ci
335e41f4b71Sopenharmony_ci
336e41f4b71Sopenharmony_ci```
337e41f4b71Sopenharmony_ciOHOS # ./mem_check --mwatch // Run the task command to obtain the mem_check process PID, which is 4.
338e41f4b71Sopenharmony_ciOHOS #
339e41f4b71Sopenharmony_ciOHOS # kill -35 4 // Check heap memory statistics.
340e41f4b71Sopenharmony_ciOHOS #
341e41f4b71Sopenharmony_ci==PID:4== Heap memory statistics(bytes):
342e41f4b71Sopenharmony_ci    [Check point]:
343e41f4b71Sopenharmony_ci        #00: <arm_signal_process+0x5c>[0x58dfc] -> /lib/libc.so
344e41f4b71Sopenharmony_ci
345e41f4b71Sopenharmony_ci    [TID: 18, Used: 0x640]
346e41f4b71Sopenharmony_ci
347e41f4b71Sopenharmony_ci==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
348e41f4b71Sopenharmony_ci
349e41f4b71Sopenharmony_ciOHOS # kill -36 4 // Check for heap memory leaks.
350e41f4b71Sopenharmony_ciOHOS #
351e41f4b71Sopenharmony_ci==PID:4== Detected memory leak(s):
352e41f4b71Sopenharmony_ci    [Check point]:
353e41f4b71Sopenharmony_ci        #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
354e41f4b71Sopenharmony_ci        #01: <arm_signal_process+0x5c>[0x58dfc] -> /lib/libc.so
355e41f4b71Sopenharmony_ci
356e41f4b71Sopenharmony_ci    [TID:18 Leak:0x320 byte(s)] Allocated from:
357e41f4b71Sopenharmony_ci        #00: <main+0x14>[0x724] -> mem_check
358e41f4b71Sopenharmony_ci        #01: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so
359e41f4b71Sopenharmony_ci
360e41f4b71Sopenharmony_ci    [TID:18 Leak:0x320 byte(s)] Allocated from:
361e41f4b71Sopenharmony_ci        #00: <func+0x14>[0x6ec] -> mem_check
362e41f4b71Sopenharmony_ci        #01: <main+0x30>[0x740] -> mem_check
363e41f4b71Sopenharmony_ci        #02: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so
364e41f4b71Sopenharmony_ci
365e41f4b71Sopenharmony_ci==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
366e41f4b71Sopenharmony_ci
367e41f4b71Sopenharmony_ciOHOS # kill -37 4 // Check the integrity of the head node of the heap memory.
368e41f4b71Sopenharmony_ciOHOS #
369e41f4b71Sopenharmony_ciCheck heap integrity ok!
370e41f4b71Sopenharmony_ci```
371e41f4b71Sopenharmony_ci
372e41f4b71Sopenharmony_ci
373e41f4b71Sopenharmony_ci##### Call Stack Parsing
374e41f4b71Sopenharmony_ci
375e41f4b71Sopenharmony_ciSave the debugging information to the **test.txt** file and use the script to parse the information to obtain the number of the line where the memory leak occurs.
376e41f4b71Sopenharmony_ci
377e41f4b71Sopenharmony_ci
378e41f4b71Sopenharmony_ci```
379e41f4b71Sopenharmony_ci$ ./parse_mem_info.sh test.txt mem_check
380e41f4b71Sopenharmony_ciCompiler is [gcc/llvm]: llvm
381e41f4b71Sopenharmony_ciNow using addr2line ...
382e41f4b71Sopenharmony_ci
383e41f4b71Sopenharmony_ci==PID:4== Detected memory leak(s):
384e41f4b71Sopenharmony_ci    [Check point]:
385e41f4b71Sopenharmony_ci        #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
386e41f4b71Sopenharmony_ci        #01: <arm_signal_process+0x5c>[0x58dfc] -> /lib/libc.so
387e41f4b71Sopenharmony_ci
388e41f4b71Sopenharmony_ci    [TID:18 Leak:0x320 byte(s)] Allocated from:
389e41f4b71Sopenharmony_ci        #00: <main+0x14>[0x724] at /usr1/xxx/TEST_ELF/mem_check.c:14
390e41f4b71Sopenharmony_ci        #01: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so
391e41f4b71Sopenharmony_ci
392e41f4b71Sopenharmony_ci    [TID:18 Leak:0x320 byte(s)] Allocated from:
393e41f4b71Sopenharmony_ci        #00: <func+0x14>[0x6ec] at /usr1/xxx/TEST_ELF/mem_check.c:8
394e41f4b71Sopenharmony_ci        #01: <main+0x30>[0x740] at /usr1/xxx/TEST_ELF/mem_check.c:19
395e41f4b71Sopenharmony_ci        #02: <(null)+0x2555a9dc>[0x219dc] -> /lib/libc.so
396e41f4b71Sopenharmony_ci
397e41f4b71Sopenharmony_ci==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
398e41f4b71Sopenharmony_ci```
399e41f4b71Sopenharmony_ci
400e41f4b71Sopenharmony_ci
401e41f4b71Sopenharmony_ci##### Running the mrecord Command
402e41f4b71Sopenharmony_ci
403e41f4b71Sopenharmony_ci1. Run the user program and specify the path of the file that stores the memory debugging information.
404e41f4b71Sopenharmony_ci
405e41f4b71Sopenharmony_ci   ```
406e41f4b71Sopenharmony_ci   OHOS # ./mem_check --mrecord /storage/check.txt
407e41f4b71Sopenharmony_ci   ```
408e41f4b71Sopenharmony_ci
409e41f4b71Sopenharmony_ci2. Run the **kill -35 <*pid*>** command to collect statistics on the memory information. The information is exported to a file. Run the **cat** command to view the information.
410e41f4b71Sopenharmony_ci
411e41f4b71Sopenharmony_ci   ```
412e41f4b71Sopenharmony_ci   OHOS # kill -35 4
413e41f4b71Sopenharmony_ci   OHOS # Memory statistics information saved in /storage/pid(4)_check.txt
414e41f4b71Sopenharmony_ci
415e41f4b71Sopenharmony_ci   OHOS # cat /storage/pid(4)_check.txt
416e41f4b71Sopenharmony_ci
417e41f4b71Sopenharmony_ci   ==PID:4== Heap memory statistics(bytes):
418e41f4b71Sopenharmony_ci       [Check point]:
419e41f4b71Sopenharmony_ci           #00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
420e41f4b71Sopenharmony_ci
421e41f4b71Sopenharmony_ci       [TID: 18, Used: 0x640]
422e41f4b71Sopenharmony_ci
423e41f4b71Sopenharmony_ci   ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
424e41f4b71Sopenharmony_ci   ```
425e41f4b71Sopenharmony_ci
426e41f4b71Sopenharmony_ci3. Run the **kill -36 <*pid*>** command to check memory integrity. The information is exported to a file. Run the **cat** command to view the information.
427e41f4b71Sopenharmony_ci
428e41f4b71Sopenharmony_ci   ```
429e41f4b71Sopenharmony_ci   OHOS # kill -36 4
430e41f4b71Sopenharmony_ci   OHOS # Leak check information saved in /storage/pid(4)_check.txt
431e41f4b71Sopenharmony_ci
432e41f4b71Sopenharmony_ci   OHOS # cat /storage/pid(4)_check.txt
433e41f4b71Sopenharmony_ci
434e41f4b71Sopenharmony_ci   ==PID:4== Heap memory statistics(bytes):
435e41f4b71Sopenharmony_ci       [Check point]:
436e41f4b71Sopenharmony_ci           #00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
437e41f4b71Sopenharmony_ci
438e41f4b71Sopenharmony_ci       [TID: 18, Used: 0x640]
439e41f4b71Sopenharmony_ci
440e41f4b71Sopenharmony_ci   ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
441e41f4b71Sopenharmony_ci
442e41f4b71Sopenharmony_ci   ==PID:4== Detected memory leak(s):
443e41f4b71Sopenharmony_ci       [Check point]:
444e41f4b71Sopenharmony_ci           #00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
445e41f4b71Sopenharmony_ci           #01: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
446e41f4b71Sopenharmony_ci
447e41f4b71Sopenharmony_ci       [TID:18 Leak:0x320 byte(s)] Allocated from:
448e41f4b71Sopenharmony_ci           #00: <main+0x14>[0x724] -> mem_check
449e41f4b71Sopenharmony_ci           #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
450e41f4b71Sopenharmony_ci
451e41f4b71Sopenharmony_ci       [TID:18 Leak:0x320 byte(s)] Allocated from:
452e41f4b71Sopenharmony_ci           #00: <func+0x14>[0x6ec] -> mem_check
453e41f4b71Sopenharmony_ci           #01: <main+0x30>[0x740] -> mem_check
454e41f4b71Sopenharmony_ci           #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
455e41f4b71Sopenharmony_ci
456e41f4b71Sopenharmony_ci   ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
457e41f4b71Sopenharmony_ci   ```
458e41f4b71Sopenharmony_ci
459e41f4b71Sopenharmony_ci4. Run the **kill -9 <*pid*>** command to kill the current process. After the process exits, a memory integrity check is performed by default. The check result is output to a file. You can run the **cat** command to view it.
460e41f4b71Sopenharmony_ci
461e41f4b71Sopenharmony_ci   ```
462e41f4b71Sopenharmony_ci   OHOS # kill -9 4
463e41f4b71Sopenharmony_ci   OHOS # Leak check information saved in /storage/pid(4)_check.txt
464e41f4b71Sopenharmony_ci
465e41f4b71Sopenharmony_ci   Check heap integrity ok!
466e41f4b71Sopenharmony_ci
467e41f4b71Sopenharmony_ci   OHOS # cat /storage/pid(4)_check.txt
468e41f4b71Sopenharmony_ci   OHOS #
469e41f4b71Sopenharmony_ci   ==PID:4== Heap memory statistics(bytes):
470e41f4b71Sopenharmony_ci       [Check point]:
471e41f4b71Sopenharmony_ci           #00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
472e41f4b71Sopenharmony_ci
473e41f4b71Sopenharmony_ci       [TID: 18, Used: 0x640]
474e41f4b71Sopenharmony_ci
475e41f4b71Sopenharmony_ci   ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
476e41f4b71Sopenharmony_ci
477e41f4b71Sopenharmony_ci   ==PID:4== Detected memory leak(s):
478e41f4b71Sopenharmony_ci       [Check point]:
479e41f4b71Sopenharmony_ci           #00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
480e41f4b71Sopenharmony_ci           #01: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
481e41f4b71Sopenharmony_ci
482e41f4b71Sopenharmony_ci       [TID:18 Leak:0x320 byte(s)] Allocated from:
483e41f4b71Sopenharmony_ci           #00: <main+0x14>[0x724] -> mem_check
484e41f4b71Sopenharmony_ci           #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
485e41f4b71Sopenharmony_ci
486e41f4b71Sopenharmony_ci       [TID:18 Leak:0x320 byte(s)] Allocated from:
487e41f4b71Sopenharmony_ci           #00: <func+0x14>[0x6ec] -> mem_check
488e41f4b71Sopenharmony_ci           #01: <main+0x30>[0x740] -> mem_check
489e41f4b71Sopenharmony_ci           #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
490e41f4b71Sopenharmony_ci
491e41f4b71Sopenharmony_ci   ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
492e41f4b71Sopenharmony_ci
493e41f4b71Sopenharmony_ci   ==PID:4== Detected memory leak(s):
494e41f4b71Sopenharmony_ci       [Check point]:
495e41f4b71Sopenharmony_ci           #00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
496e41f4b71Sopenharmony_ci           #01: <exit+0x28>[0x11b2c] -> /lib/libc.so
497e41f4b71Sopenharmony_ci
498e41f4b71Sopenharmony_ci       [TID:18 Leak:0x320 byte(s)] Allocated from:
499e41f4b71Sopenharmony_ci           #00: <main+0x14>[0x724] -> mem_check
500e41f4b71Sopenharmony_ci           #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
501e41f4b71Sopenharmony_ci
502e41f4b71Sopenharmony_ci       [TID:18 Leak:0x320 byte(s)] Allocated from:
503e41f4b71Sopenharmony_ci           #00: <func+0x14>[0x6ec] -> mem_check
504e41f4b71Sopenharmony_ci           #01: <main+0x30>[0x740] -> mem_check
505e41f4b71Sopenharmony_ci           #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
506e41f4b71Sopenharmony_ci
507e41f4b71Sopenharmony_ci   ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
508e41f4b71Sopenharmony_ci   ```
509e41f4b71Sopenharmony_ci
510e41f4b71Sopenharmony_ci> **NOTE**<br>
511e41f4b71Sopenharmony_ci> The preceding information recorded gradually is added to the file specified during initialization. Therefore, running the **cat** command can also display the historical information in the file.
512e41f4b71Sopenharmony_ci## Common Problems
513e41f4b71Sopenharmony_ci
514e41f4b71Sopenharmony_ci
515e41f4b71Sopenharmony_ci### Use After Free (UAF)
516e41f4b71Sopenharmony_ci
517e41f4b71Sopenharmony_ci- Requested memory less than or equal to 0x1c000 bytes:
518e41f4b71Sopenharmony_ci  
519e41f4b71Sopenharmony_ci  Read operation: If the magic number (0xFEFEFEFE) is read from the memory block released, UAF occurs.
520e41f4b71Sopenharmony_ci  
521e41f4b71Sopenharmony_ci  > **NOTE**
522e41f4b71Sopenharmony_ci  >
523e41f4b71Sopenharmony_ci  > After **free** is called, the heap memory will not be released to the heap memory pool immediately. Instead, the heap memory is placed in a queue with a fixed length and filled with the magic number 0xFE. When the queue is full, the memory block first placed in the queue is released to the heap memory pool first.
524e41f4b71Sopenharmony_ci  
525e41f4b71Sopenharmony_ci  Write operation: The memory debugging module cannot detect UAF errors from write operations.
526e41f4b71Sopenharmony_ci
527e41f4b71Sopenharmony_ci
528e41f4b71Sopenharmony_ci- Requested memory block greater than 0x1c000 bytes:
529e41f4b71Sopenharmony_ci  
530e41f4b71Sopenharmony_ci  The heap memory greater than 0x1c000 bytes must be requested by calling the **mmap** API via **malloc**. If the heap memory is accessed after being released, the user program will become abnormal (because the memory region has been unmapped).
531e41f4b71Sopenharmony_ci
532e41f4b71Sopenharmony_ci
533e41f4b71Sopenharmony_ci### Double Free
534e41f4b71Sopenharmony_ci
535e41f4b71Sopenharmony_ciDouble free errors occur when **free()** is called more than once with the same memory address as an argument. When a double free error occurs, the user program exits unexpectedly.
536e41f4b71Sopenharmony_ci
537e41f4b71Sopenharmony_ci
538e41f4b71Sopenharmony_ci### Heap Memory Node Corrupted
539e41f4b71Sopenharmony_ci
540e41f4b71Sopenharmony_ci- Requested memory block less than or equal to 0x1c000 bytes:
541e41f4b71Sopenharmony_ci
542e41f4b71Sopenharmony_ci  When a heap memory node is corrupted, the user program exits unexpectedly, and the call stack that requests the heap memory of the node corrupted is output. The memory debugging module, however, cannot debug the memory corrupted by a wild pointer. For example, if the user program mem_check has heap memory overwriting, you can use the command line to obtain the possible location of the memory corruption.
543e41f4b71Sopenharmony_ci
544e41f4b71Sopenharmony_ci
545e41f4b71Sopenharmony_ci  ```
546e41f4b71Sopenharmony_ci  OHOS # ./mem_check --mwatch
547e41f4b71Sopenharmony_ci  OHOS #
548e41f4b71Sopenharmony_ci  ==PID:6== Memory integrity information:
549e41f4b71Sopenharmony_ci      [TID:28 allocated addr: 0x272e1ea0, size: 0x120] The possible attacker was allocated from:
550e41f4b71Sopenharmony_ci          #00: <malloc+0x808>[0x640e8] -> /lib/libc.so
551e41f4b71Sopenharmony_ci          #01: <threadFunc1+0x7c>[0x21d0] -> mem_check
552e41f4b71Sopenharmony_ci  ```
553e41f4b71Sopenharmony_ci
554e41f4b71Sopenharmony_ci  You can use the call stack parsing script to parse the call stack information.
555e41f4b71Sopenharmony_ci
556e41f4b71Sopenharmony_ci- Requested memory block greater than 0x1c000 bytes:
557e41f4b71Sopenharmony_ci
558e41f4b71Sopenharmony_ci  When a large memory block (greater than 0x1c000 bytes) is requested by calling the **mmap** API via **malloc**, one more page of **PAGE_SIZE** is allocated at the start and end of the memory region. The two pages are neither readable nor writeable. Any read or write operation to the pages may cause an exception of the user program.
559