2016-06-21 130 views
0

以下C代码将导致传递0xFFFFFFFFFFFFFFFFmalloc()而不是预期的0,由Visual Studio 2013编译为64时:奇怪代码2013

#include <stdlib.h> 

int main(int argc, char *argv[]) { 
    int x = -1; 
    void *p = malloc(x + 1); 
} 

打开拆卸视图揭示了这种奇怪的片断(调试配置,虽然推出在功能上是相同的):

; int x = -1; 
mov   dword ptr [x],0FFFFFFFFh 
; void *p = malloc(x + 1); 
mov   eax,dword ptr [x] 
add   eax,1 
mov   eax,eax 
mov   rcx,0FFFFFFFFFFFFFFFFh 
cmovb  rax,rcx 
mov   rcx,rax 
call  qword ptr [__imp_malloc (07F79C80B228h)] 
mov   qword ptr [p],rax 

铸造为size_t不会改变任何东西,但结果存储到临时变量,然后将它传递给malloc()会。

奇怪的是,在调用同样声明的任何其他功能时,不会发生这种情况:

void * __cdecl foo(size_t y) { 
    return NULL; 
} 

int main(int argc, char *argv[]) { 
    int x = -1; 
    void *p = foo(x + 1); 
} 

在这种情况下,会生成正确的代码(注意失踪cmovb东西):

; int x = -1; 
mov   dword ptr [x],0FFFFFFFFh 
; void *p = foo(x + 1); 
mov   eax,dword ptr [x] 
inc   eax 
cdqe 
mov   rcx,rax 
call  foo (07F6AB84100Ah) 
mov   qword ptr [p],rax 

我犹豫称这是一个代码生成错误。我必须认为这是我错过的东西。但是,我从来没有见过这种情况,它肯定会产生不正确的行为。

这是怎么发生的?

+0

'main'应该返回'int',而不是'void'。我在clang中看到了一些使'char'始终未被签名的选项。也许你的'int'会发生同样的情况,但我不确定。 – ForceBru

+1

那么,它是实现定义是否[m/c/re] alloc(0)'返回NULL或无法取消引用的有效指针。这可能是Visual Studio将'SIZE_MAX'传递给'malloc()'以确保分配失败,在这种情况下返回NULL。 – EOF

+0

https://msdn.microsoft.com/en-us/library/jj161081.aspx –

回答

2

这是防范整数溢出(如评论here中引用)。

如果传递给malloc的值是整数溢出(有符号或无符号)的结果,而不是让程序分配比编译器认为的更少的内存,则最大化表达式并尝试分配该内存。

+0

只是旁注:由于值0xFFFFFFFFFFFFFFFF超过_HEAP_MAXREQ,它是0xFFFFFFFFFFFFFFE0,'malloc'将导致errno中出现ENOMEM错误 –