malloc(3)に負の値を渡すと
「詳説Cポインタ」p43より。
2.2.1 malloc関数の使い方 (略) void* malloc(size_t); malloc関数はsize_t型の引数を1つ取ります。この型は1章で扱いました。引数に値を指定する際には、 注意が必要です。負の値を指定した場合には、問題となります。システムによっては、引数が負の値で あった場合には、NULLが返ります。
malloc(3)の引数に例えば-1を指定した場合ですが、malloc(3)の引数であるsize_tにキャストされた値で処理されます。size_tの型は、うちの環境だとこうです。
/* /usr/lib/gcc/x86_64-redhat-linux/4.4.4/include/stddef.h */ 25 /* 26 * ISO C Standard: 7.17 Common definitions <stddef.h> 27 */ (略) 207 #ifndef __SIZE_TYPE__ 208 #define __SIZE_TYPE__ long unsigned int 209 #endif 210 #if !(defined (__GNUG__) && defined (size_t)) 211 typedef __SIZE_TYPE__ size_t; 212 #ifdef __BEOS__ 213 typedef long ssize_t; 214 #endif /* __BEOS__ */ 215 #endif /* !(defined (__GNUG__) && defined (size_t)) */
size_t型は、「__SIZE_TYPE__」(でマクロ定義された型名)の別名に定義されており、__SIZE_TYPE__はlong unsigned intにマクロ展開されます。
つまり、malloc(3)の引数に-1を指定した場合、-1はlong unsigned intに型変換されます。64ビット環境で0xFFFFFFFFFFFFFFFF、10進数で2^64-1。32ビット環境だと、4294967295、つまり4GB。このサイズが要求サイズに指定されるため、結果的にメモり不足エラーが返ってくるのでは、と考えられます。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <errno.h> 4 5 extern int errno; 6 7 int main(int argc, char **argv){ 8 9 char *p; 10 int errno_sv; 11 12 errno = 0; 13 p = malloc(-1); 14 errno_sv = errno; 15 16 printf("errno=%d p=%p\n", errno_sv, p); 17 printf("sizeof(size_t)=%zd\n", sizeof(size_t)); 18 19 return 0; 20 }
実行結果
errno=12 p=(nil) sizeof(size_t)=8
malloc(3)の戻り値にはNULLが返され、errnoに12(ENOMEM=Not enough space (POSIX.1) )がセットされました。
以下は、該当コード部分の逆アセンブル結果です。-1も(+2^64-1)も、内部表現は同じなので、malloc(3)側がこの値を符号ありとして扱うか、符号無しとして扱うかは、malloc(3)内部を見ないと判断できないですが。
p = malloc(-1); 40057e: 48 c7 c7 ff ff ff ff mov rdi,0xffffffffffffffff 400585: e8 be fe ff ff call 400448 <malloc@plt>
引数に、(+2^64-1)を指定した場合。
p = malloc(0xFFFFFFFFFFFFFFFF); 40057e: 48 c7 c7 ff ff ff ff mov rdi,0xffffffffffffffff 400585: e8 be fe ff ff call 400448 <malloc@plt>