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>