2016-06-21 109 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錯誤 –