您的位置:首页 > 其它

/proc/sys/vm/max_map_count耗尽时,调用glibc 2.11.3 free()导致程序crash,问题追踪和解决

2017-12-15 14:45 639 查看


1. 问题

在客户环境下,当我们的程序消耗较大内存时,会偶尔crash。

通过gdb分析,程序core dump在malloc/free函数内。

当把/proc/sys/vm/max_map_count 从65530增加到131070,程序再也不crash。

相关命令 echo 131073 > /proc/sys/vm/max_map_count


2.  core dump 分析

Thread 1 (Thread 20074): #0  0x00007fbb77afd6d5 in raise () from/lib64/libc.so.6 

#1  0x00007fbb77afecb1in abort () from /lib64/libc.so.6 

#2 0x00007fbb77b43a0d in __malloc_assert () from /lib64/libc.so.6 #3  0x00007fbb787ea6a8 in 

#3 不再给出,涉及保密

...

...

运行环境是SUSE 11 SP3, 其glibc 版本是2.11.3。

通过读glibc 2.11.3 代码,发现一个可疑点:

https://github.com/lzueclipse/learning/blob/master/c_cpp/glibc-2.11.3/malloc/malloc.c#L3552


当free()时,如果/proc/sys/vm/max_map_count 被耗尽,那么munmap系统调用会失败,就会导致assert,并core dump。

下面我们来试图证明这个分析是正确的。


3. 通过Google搜索找到一个类似的问题

Google搜索“munmap_chunk assert”,找到:

https://sourceware.org/bugzilla/show_bug.cgi?id=13276

报的问题是:

When a process runs out of virtual mappings on Linux (more mmaps than /proc/sys/vm/max_map_count) then munmap can fail because it  may need to split a mapping.

在这个bug下面,给出了一个重现这个bug的test case:

https://sourceware.org/bugzilla/attachment.cgi?id=5967

我在第4节中会利用这个测试用例重现bug。

针对这个bug的fix:

https://www.sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=6ef76f3b515c45a83f7831f806bf97a2af9ed008


-  int ret __attribute__ ((unused)) = munmap((char *)block, total_size);

-

-  /* munmap returns non-zero on failure */

-  assert(ret == 0);

+  /* If munmap failed the process virtual memory address space is in a

+     bad shape.  Just leave the block hanging around, the process will

+     terminate shortly anyway since not much can be done.  */

+  munmap((char *)block, total_size);

 }

可以看出,当munmap失败时,glibc不在assert,这个fix在glibc 2.15以及后续版本中。


4. 测试并重现bug


4.1 代码和测试环境



https://sourceware.org/bugzilla/attachment.cgi?id=5967

进行了少量修改,以便我加入一些pmap调试信息,我的代码在:

https://github.com/lzueclipse/learning/blob/master/c_cpp/malloc_free_bug_2.11.3/mmap_malloc_test.c





测试将在SUSE 11 SP3(glibc 2.11.3)和SUSE 12(glibc 2.19)上进行,期望的行为是:

程序在SUSE 11 SP3 crash,但是在SUSE 12上运行正常。


4.2 在SUSE 11 SP3上的测试

1)ulimit -c unlimited

 不限制core file大小。

2) gcc -g mmap_malloc_test.c

编译,有符号。

3) ./a.out

cnt=65530, ps=4096

.........

19

.........

19

.........

19

.........

65531

a.out: malloc.c:3546: munmap_chunk: Assertion `ret == 0'failed.

Aborted (core dumped)   

 可以看出:

“/proc/sys/vm/max_map_count” 的值是65530,当超过它时(65531),crash在了free()。

pmap调试信息在:

https://github.com/lzueclipse/learning/blob/master/c_cpp/malloc_free_bug_2.11.3/pmap1.txt


https://github.com/lzueclipse/learning/blob/master/c_cpp/malloc_free_bug_2.11.3/pmap2.txt


https://github.com/lzueclipse/learning/blob/master/c_cpp/malloc_free_bug_2.11.3/pmap3.txt


https://raw.githubusercontent.com/lzueclipse/learning/master/c_cpp/malloc_free_bug_2.11.3/pmap4.txt


4) gdb -c ./core a.out

GNU gdb (GDB) SUSE (7.5.1-0.7.29)

Copyright (C) 2012 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law.  Type "show copying"

and "show warranty" for details.

This GDB was configured as "x86_64-suse-linux".

For bug reporting instructions, please see:

<http://www.gnu.org/software/gdb/bugs/>...

Reading symbols from /home/robinwan/public_html/a.out...done.

[New LWP 9003]

Missing separate debuginfo for /lib64/libc.so.6

Try: zypper install -C

"debuginfo(build-id)=89f460a6502702332c336f3cd7f5568036483b98"

Missing separate debuginfo for /lib64/ld-linux-x86-64.so.2

Try: zypper install -C

"debuginfo(build-id)=38ab807fcca391af7d3ed7fcf585fbff2d54556a"

Core was generated by `./a.out'.

Program terminated with signal 6, Aborted.

#0  0x00007fd5f369db55 in raise () from /lib64/libc.so.6

(gdb) bt

#0  0x00007fd5f369db55 in raise () from /lib64/libc.so.6

#1  0x00007fd5f369f131 in abort () from /lib64/libc.so.6

#2  0x00007fd5f36e183d in __malloc_assert () from /lib64/libc.so.6

#3  0x000000000040097d in main () at mmap_malloc_test.c:42  《======42行,就是free().


4.3 在SUSE 12上的测试

./a.out

cnt=65530, ps=4096

.........

19

.........

19

.........

19

.........

65531

.........

end!!!

“/proc/sys/vm/max_map_count” 的值是65530,当超过它时(65531),没有crash。


5.结论

一旦遇到类似问题,如果glibc版本是2.11.x ---2.14.x,只能增加“/proc/sys/vm/max_map_count”;

从glibc 2.15.x,这个问题已经被修复。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐