I'm very new to C programming and investigating continuously increasing RSS size. The suspicion is there is some memory leak. I looked at the /proc/<pid>/maps and found the following:
f8000000-fb180000 rw-p 00000000 00:00 0
fb180000-fd580000 ---p 00000000 00:00 0
fd580000-fdc80000 rw-p 00000000 00:00 0
fdc80000-100000000 ---p 00000000 00:00 0
100000000-1005a0000 rw-p 00000000 00:00 0
1005a0000-140000000 ---p 00000000 00:00 0
7fb45d1dd000-7fb45d1e0000 ---p 00000000 00:00 0
7fb45e0ec000-7fb45e0ef000 ---p 00000000 00:00 0
7fb45e0ef000-7fb45e1ed000 rw-p 00000000 00:00 0
7fb45e1ed000-7fb45e1f0000 ---p 00000000 00:00 0
7fb45e1f0000-7fb45e2ee000 rw-p 00000000 00:00 0
7fb45e2ee000-7fb45e2f1000 ---p 00000000 00:00 0
7fb45e2f1000-7fb45e3ef000 rw-p 00000000 00:00 0
7fb45e3ef000-7fb45e3f2000 ---p 00000000 00:00 0
7fb45e3f2000-7fb45e4f0000 rw-p 00000000 00:00 0
7fb45e4f0000-7fb45e4f3000 ---p 00000000 00:00 0
7fb45e4f3000-7fb45e5f1000 rw-p 00000000 00:00 0
7fb45e5f1000-7fb45e5f4000 ---p 00000000 00:00 0
7fb45e5f4000-7fb45e6f2000 rw-p 00000000 00:00 0
7fb45e6f2000-7fb45e6f5000 ---p 00000000 00:00 0
7fb45e6f5000-7fb45e7f3000 rw-p 00000000 00:00 0
7fb45e7f3000-7fb45e7f6000 ---p 00000000 00:00 0
7fb45e7f6000-7fb45e8f4000 rw-p 00000000 00:00 0
7fb45e8f4000-7fb45e8f7000 ---p 00000000 00:00 0
//Tons of the similar entries...
7fb71652b000-7fb71652c000 rw-p 0001a000 08:01 2187 /lib/x86_64-linux-gnu/libpthread-2.27.so
7fb716568000-7fb71656f000 r--s 00000000 08:01 5020 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
7fb716759000-7fb71675a000 rw-p 00000000 00:00 0
7ffc5f781000-7ffc5f7a2000 rw-p 00000000 00:00 0 [stack]
7ffc5f7c7000-7ffc5f7ca000 r--p 00000000 00:00 0 [vvar]
7ffc5f7ca000-7ffc5f7cc000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
The thing that I noticed was that the vast majority of /proc/<pid>/maps were entries like:
7fb45e7f3000-7fb45e7f6000 ---p 00000000 00:00 0
What does this mean? Doesn't it mean that system allocator release the memory it acquires?
Is there a way to examine the memory content at address, e.g. 7fb45e5f4000-7fb45e6f2000 at run-time?
I tried to attach to the running process with gdb and looked at the memory.
(gdb) x /1xg 0x7fb45e1ed000
0x5e1ed000: Cannot access memory at address 0x5e1ed000
Entries like
7fb45e0ec000-7fb45e0ef000 ---p 00000000 00:00 0
7fb45e0ef000-7fb45e1ed000 rw-p 00000000 00:00 0
look like thread stacks and their associated guard pages.
It looks like you create a lot of threads, but neither reap them via pthread_join(), or detach them via pthread_detach() (or create them in detached state).
Non-detached threads must be reaped to return their resources (stack, specifically) to the OS.
Related
I am wondering if there is any simple/neat way in C to detect if a given memory range (A, A+len) falls under the process address space?
EDIT:
My use case is more for reverse engineering and locating some strings (or fixed sized structs) in memory. So even a hacky test will work right for me to narrow down my search.
On Linux, read /proc/$pid/maps. It contains a textual description of the memory ranges mapped by a process, e.g.
00400000-0040b000 r-xp 00000000 08:00 35402 /bin/cat
0060a000-0060b000 r--p 0000a000 08:00 35402 /bin/cat
0060b000-0060c000 rw-p 0000b000 08:00 35402 /bin/cat
006ab000-006cc000 rw-p 00000000 00:00 0 [heap]
7f9a73235000-7f9a734fe000 r--p 00000000 08:00 949 /usr/lib/locale/locale-archive
7f9a734fe000-7f9a736b8000 r-xp 00000000 08:00 18124 /lib/x86_64-linux-gnu/libc-2.19.so
7f9a736b8000-7f9a738b8000 ---p 001ba000 08:00 18124 /lib/x86_64-linux-gnu/libc-2.19.so
7f9a738b8000-7f9a738bc000 r--p 001ba000 08:00 18124 /lib/x86_64-linux-gnu/libc-2.19.so
7f9a738bc000-7f9a738be000 rw-p 001be000 08:00 18124 /lib/x86_64-linux-gnu/libc-2.19.so
7f9a738be000-7f9a738c3000 rw-p 00000000 00:00 0
7f9a738c3000-7f9a738e6000 r-xp 00000000 08:00 17952 /lib/x86_64-linux-gnu/ld-2.19.so
7f9a73ad9000-7f9a73adc000 rw-p 00000000 00:00 0
7f9a73ae3000-7f9a73ae5000 rw-p 00000000 00:00 0
7f9a73ae5000-7f9a73ae6000 r--p 00022000 08:00 17952 /lib/x86_64-linux-gnu/ld-2.19.so
7f9a73ae6000-7f9a73ae7000 rw-p 00023000 08:00 17952 /lib/x86_64-linux-gnu/ld-2.19.so
7f9a73ae7000-7f9a73ae8000 rw-p 00000000 00:00 0
7ffde1b80000-7ffde1ba1000 rw-p 00000000 00:00 0 [stack]
7ffde1bd5000-7ffde1bd7000 r--p 00000000 00:00 0 [vvar]
7ffde1bd7000-7ffde1bd9000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
There's a lot of information here, but what matters to you is the first two columns. The first one is an address range, and the second one is the access privileges it's mapped with.
Note that this has a distinct advantage over any approach based around triggering segfaults: it can be read from another process, and doesn't require any code to be added to the target process.
This question already has answers here:
When / How does Linux load shared libraries into address space?
(5 answers)
Closed 9 years ago.
On linux platform,
Could anyone tell me where is the dynamic library in the memory?
I learned that the dynamic library are mmap to the process according to the GOT
of this process,
is that true?
Thank you!
You can see where things got mapped in a Linux process by looking in /proc/pid/maps -- all you need to know is the process id. For example:
$ cat /proc/self/maps
00400000-0040b000 r-xp 00000000 08:01 71827604 /bin/cat
0060a000-0060b000 r--p 0000a000 08:01 71827604 /bin/cat
0060b000-0060c000 rw-p 0000b000 08:01 71827604 /bin/cat
00690000-006b1000 rw-p 00000000 00:00 0 [heap]
7f07fbaf7000-7f07fbdc0000 r--p 00000000 08:01 18094104 /usr/lib/locale/locale-archive
7f07fbdc0000-7f07fbf75000 r-xp 00000000 08:01 14552996 /lib/x86_64-linux-gnu/libc-2.15.so
7f07fbf75000-7f07fc175000 ---p 001b5000 08:01 14552996 /lib/x86_64-linux-gnu/libc-2.15.so
7f07fc175000-7f07fc179000 r--p 001b5000 08:01 14552996 /lib/x86_64-linux-gnu/libc-2.15.so
7f07fc179000-7f07fc17b000 rw-p 001b9000 08:01 14552996 /lib/x86_64-linux-gnu/libc-2.15.so
7f07fc17b000-7f07fc180000 rw-p 00000000 00:00 0
7f07fc180000-7f07fc1a2000 r-xp 00000000 08:01 14553008 /lib/x86_64-linux-gnu/ld-2.15.so
7f07fc37e000-7f07fc381000 rw-p 00000000 00:00 0
7f07fc3a0000-7f07fc3a2000 rw-p 00000000 00:00 0
7f07fc3a2000-7f07fc3a3000 r--p 00022000 08:01 14553008 /lib/x86_64-linux-gnu/ld-2.15.so
7f07fc3a3000-7f07fc3a5000 rw-p 00023000 08:01 14553008 /lib/x86_64-linux-gnu/ld-2.15.so
7fff90e28000-7fff90e49000 rw-p 00000000 00:00 0 [stack]
7fff90f1f000-7fff90f20000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
shows everything that got mapped in to run the cat program.
I could identify the text, ds and bss segments in /proc/$PID/maps file (by guessing or with the help of access-specifiers of a particular segment). But heap and stack segments are given sequently. Is there a way to identify which segment belongs to stack and which belongs to heap?
----- How to identify the demarkation between heap and stack in this example ----------
0a8a0000-0ab2e000 rw-p 0a8a0000 00:00 0 [heap]
< b648e000-b648f000 ---p b648e000 00:00 0
< b648f000-b6496000 rw-p b648f000 00:00 0
< b6496000-b6497000 ---p b6496000 00:00 0
< b6497000-b649e000 rw-p b6497000 00:00 0
< b649e000-b649f000 ---p b649e000 00:00 0
< b649f000-b64a6000 rw-p b649f000 00:00 0
< b64a6000-b64a7000 ---p b64a6000 00:00 0
< b64a7000-b64ae000 rw-p b64a7000 00:00 0
< b64ae000-b64af000 ---p b64ae000 00:00 0
< b64af000-b657a000 rw-p b64af000 00:00 0
< b657a000-b657b000 ---p b657a000 00:00 0
< b657b000-b65a5000 rw-p b657b000 00:00 0
< b65a5000-b65a6000 ---p b65a5000 00:00 0
< b65a6000-b67ca000 rw-p b65a6000 00:00 0
< b67ca000-b67cb000 ---p b67ca000 00:00 0
< b67cb000-b69ff000 rw-p b67cb000 00:00 0
< b69ff000-b6a00000 ---p b69ff000 00:00 0
< b6a00000-b6bff000 rw-p b6a00000 00:00 0
< b6bff000-b6c00000 ---p b6bff000 00:00 0
< b6c00000-b6dff000 rw-p b6c00000 00:00 0
< b6dff000-b6e00000 ---p b6dff000 00:00 0
< b6e00000-b6fff000 rw-p b6e00000 00:00 0
< b6fff000-b7000000 ---p b6fff000 00:00 0
< b7000000-b70fd000 rw-p b7000000 00:00 0
< b70fd000-b70fe000 ---p b70fd000 00:00 0
< b70fe000-b72fd000 rw-p b70fe000 00:00 0
< b72fd000-b72fe000 ---p b72fd000 00:00 0
< b72fe000-b7548000 rw-p b72fe000 00:00 0
< b7548000-b7549000 ---p b7548000 00:00 0
< b7549000-b7f37000 rw-p b7549000 00:00 0
< b7f4b000-b7f4c000 ---p b7f4b000 00:00 0
< b7f4c000-b7f51000 rw-p b7f4c000 00:00 0
< bfbae000-bfbc3000 rw-p bffea000 00:00 0 [stack]
The /proc/PID/maps file containing the currently mapped memory regions and
their access permissions.
The format is:
address perms offset dev inode pathname
08048000-08049000 r-xp 00000000 03:00 8312 /opt/test
08049000-0804a000 rw-p 00001000 03:00 8312 /opt/test
0804a000-0806b000 rw-p 00000000 00:00 0 [heap]
a7cb1000-a7cb2000 ---p 00000000 00:00 0
a7cb2000-a7eb2000 rw-p 00000000 00:00 0
a7eb2000-a7eb3000 ---p 00000000 00:00 0
a7eb3000-a7ed5000 rw-p 00000000 00:00 0 [stack:1001]
a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6
a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6
a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6
a800b000-a800e000 rw-p 00000000 00:00 0
a800e000-a8022000 r-xp 00000000 03:00 14462 /lib/libpthread.so.0
a8022000-a8023000 r--p 00013000 03:00 14462 /lib/libpthread.so.0
a8023000-a8024000 rw-p 00014000 03:00 14462 /lib/libpthread.so.0
a8024000-a8027000 rw-p 00000000 00:00 0
a8027000-a8043000 r-xp 00000000 03:00 8317 /lib/ld-linux.so.2
a8043000-a8044000 r--p 0001b000 03:00 8317 /lib/ld-linux.so.2
a8044000-a8045000 rw-p 0001c000 03:00 8317 /lib/ld-linux.so.2
aff35000-aff4a000 rw-p 00000000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
where "address" is the address space in the process that it occupies, "perms"
is a set of permissions:
r = read
w = write
x = execute
s = shared
p = private (copy on write)
"offset" is the offset into the mapping, "dev" is the device (major:minor), and
"inode" is the inode on that device. 0 indicates that no inode is associated
with the memory region, as the case would be with BSS (uninitialized data).
The "pathname" shows the name associated file for this mapping. If the mapping
is not associated with a file:
[heap] = the heap of the program
[stack] = the stack of the main process
[stack:1001] = the stack of the thread with tid 1001
[vdso] = the "virtual dynamic shared object",
the kernel system call handler
or if empty, the mapping is anonymous.
(Source https://www.kernel.org/doc/Documentation/filesystems/proc.txt)
Can anybody tell me what is a proc map? How it is useful and how to check it?
Thanks in advance.
Here is one of the proc maps, can someone explain what does it signify?
enter code here
-bash-3.2# cat /proc/2064/maps
00008000-00009000 r-xp 00000000 00:0e 33036189 /tmp/efence/dev.out
00010000-00011000 rw-p 00000000 00:0e 33036189 /tmp/efence/dev.out
00011000-00032000 rw-p 00011000 00:00 0 [heap]
40000000-4001d000 r-xp 00000000 00:0e 32247424 /devel/lib/ld-2.9.so
4001d000-40020000 rw-p 4001d000 00:00 0
40024000-40025000 r--p 0001c000 00:0e 32247424 /devel/lib/ld-2.9.so
40025000-40026000 rw-p 0001d000 00:0e 32247424 /devel/lib/ld-2.9.so
40030000-40157000 r-xp 00000000 00:0e 32247431 /devel/lib/libc-2.9.so
40157000-4015f000 ---p 00127000 00:0e 32247431 /devel/lib/libc-2.9.so
4015f000-40161000 r--p 00127000 00:0e 32247431 /devel/lib/libc-2.9.so
40161000-40162000 rw-p 00129000 00:0e 32247431 /devel/lib/libc-2.9.so
40162000-40165000 rw-p 40162000 00:00 0
beb58000-beb6d000 rw-p befeb000 00:00 0 [stack]
The file /proc/[pid]/maps is a way to see the memory regions mapped by a process. Read about /proc for more info on other useful stuff you can find there.
I just want to know where is (if present!) the Heap of my bash process (pid = 16457) in the result of cat /proc/16457/maps
0078a000-007a0000 r-xp 00000000 08:02 1319336 /lib/ld-2.3.4.so
007a0000-007a1000 r--p 00015000 08:02 1319336 /lib/ld-2.3.4.so
007a1000-007a2000 rw-p 00016000 08:02 1319336 /lib/ld-2.3.4.so
007a9000-008cf000 r-xp 00000000 08:02 1384495 /lib/tls/libc-2.3.4.so
008cf000-008d1000 r--p 00125000 08:02 1384495 /lib/tls/libc-2.3.4.so
008d1000-008d3000 rw-p 00127000 08:02 1384495 /lib/tls/libc-2.3.4.so
008d3000-008d5000 rw-p 008d3000 00:00 0
008fc000-008fe000 r-xp 00000000 08:02 1319337 /lib/libdl-2.3.4.so
008fe000-008ff000 r--p 00001000 08:02 1319337 /lib/libdl-2.3.4.so
008ff000-00900000 rw-p 00002000 08:02 1319337 /lib/libdl-2.3.4.so
00b27000-00b2a000 r-xp 00000000 08:02 278109 /lib/libtermcap.so.2.0.8
00b2a000-00b2b000 rw-p 00002000 08:02 278109 /lib/libtermcap.so.2.0.8
08047000-080d8000 r-xp 00000000 08:02 902412 /bin/bash
080d8000-080de000 rw-p 00090000 08:02 902412 /bin/bash
080de000-080e3000 rw-p 080de000 00:00 0
09ceb000-09d25000 rw-p 09ceb000 00:00 0
b7d99000-b7d9b000 rw-p b7d99000 00:00 0
b7d9b000-b7da1000 r--s 00000000 08:02 130808 /usr/lib/gconv/gconv-modules.cache
b7da1000-b7dd6000 r--s 00000000 08:02 869910 /var/db/nscd/passwd
b7dd6000-b7fd6000 r--p 00000000 08:02 101088 /usr/lib/locale/locale-archive
b7fd6000-b7fd8000 rw-p b7fd6000 00:00 0
bff07000-c0000000 rw-p bff07000 00:00 0
ffffe000-fffff000 r-xp 00000000 00:00 0
"The" heap most people refer to is this line:
080de000-080e3000 rw-p 080de000 00:00 0
i.e. it's the region of memory created and expandable by the brk syscall, immediately following the main program's .data and .bss segments.
One might also consider the following as part of the "heap":
09ceb000-09d25000 rw-p 09ceb000 00:00 0
It seems to be an anonymous mapping created by mmap to service a large malloc request. Most malloc implementations use mmap for large requests so they can munmap it on free and return the whole block of memory to the OS. It also makes calloc much faster since you're guaranteed to get per-zeroed pages this way.
The heap is clearly marked as [heap] in current Linux versions. Your listing doesn't show it. Are you sure you didn't accidentally cut it out when copying it to your question?
On my shell:
~% grep '\[heap' /proc/$$/maps
00bca000-00d2e000 rw-p 00000000 00:00 0 [heap]
The heap usually appears to be marked with [heap] when a malloc call is called; however, you'll notice that if you keep growing the heap with multiple lines of malloc() code that range will not grow; however, new blank line entries will be created.