一个小坑

昨天在编译uClibc-ng中提取出来的malloc堆内存分配器时, 踩了一个小坑, 特此记录。

故事是这样的, 我在编译(开启了gcc的O2)相关代码为so之后对其进行测试, 测试到calloc函数时卡死。经过gdb等工具的调试, 我最终发现calloc函数编译生成的汇编代码是一个死循环。

原始C代码如下所示(即uClibc-ng的calloc实现):

void * calloc(size_t nmemb, size_t lsize)
{
    void *result;
    size_t size=lsize * nmemb;

    /* guard vs integer overflow, but allow nmemb
     * to fall through and call malloc(0) */
    if (nmemb && lsize != (size / nmemb)) {
        __set_errno(ENOMEM);
        return NULL;
    }
    if ((result=malloc(size)) != NULL) {
        memset(result, 0, size);
    }
    return result;
}

死循环汇编代码如下所示:

0000000000000840 <calloc>:
 840:	48 89 f1             	mov    %rsi,%rcx
 843:	48 0f af cf          	imul   %rdi,%rcx
 847:	48 85 ff             	test   %rdi,%rdi
 84a:	74 0d                	je     859 <calloc+0x19>
 84c:	31 d2                	xor    %edx,%edx
 84e:	48 89 c8             	mov    %rcx,%rax
 851:	48 f7 f7             	div    %rdi
 854:	48 39 f0             	cmp    %rsi,%rax
 857:	75 17                	jne    870 <calloc+0x30>
 859:	be 01 00 00 00       	mov    $0x1,%esi
 85e:	48 89 cf             	mov    %rcx,%rdi
 861:	e9 8a fe ff ff       	jmpq   6f0 <calloc@plt>
 866:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
 86d:	00 00 00 
 870:	48 83 ec 08          	sub    $0x8,%rsp
 874:	e8 67 fe ff ff       	callq  6e0 <__errno_location@plt>
 879:	c7 00 0c 00 00 00    	movl   $0xc,(%rax)
 87f:	31 c0                	xor    %eax,%eax
 881:	48 83 c4 08          	add    $0x8,%rsp
 885:	c3                   	retq   
 886:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
 88d:	00 00 00

注: calloc@plt的符号最后会被解析到840 calloc, 于是变为一个死循环。

进一步研究发现, gcc在开启O2的情况下, 会假设程序中调用的malloc、calloc、realloc以及free等函数是glibc的实现, 并对其做特定优化。在这个例子中, malloc和它后面的memset被优化为了对calloc的调用, 结合尾递归优化, 变为了死循环。

解决办法是在编译时加入”-fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free”参数, 防止gcc的这类优化, 因为我们正在实现一个malloc库。

发表评论

注意 - 你可以用以下 HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

:wink: :twisted: :roll: :oops: :mrgreen: :lol: :idea: :evil: :cry: :arrow: :?: :-| :-x :-o :-P :-D :-? :) :( :!: 8-O 8)

本文链接:https://twd2.me/archives/11957QrCode