这个malloc应该不起作用

这是我的代码。

int main() { char *s; int i = 0; printf("%lu \n", sizeof(s)); s = malloc(sizeof(char) * 2); printf("%lu \n", sizeof(s)); /*Why is this working?*/ while (i <= 5) { s[i] = 'l'; i++; } printf("%s \n", s); printf("%lu \n", sizeof(char)); printf("%lu \n", sizeof(s[0])); } 

在我看来,这应该是段错误,因为我试图写的比我分配的更多。 这为何有效?

在插图 (并完全同意)@Ed S的答案中 ,尝试这个代码示例,添加一个额外的变量,以完全相同的方式声明,并在char *s之后立即进行malloc。

虽然不能保证变量按顺序存储在内存中,但以这种方式创建它们很有可能。 如果是这样char *t现在将拥有char *s将侵占的空间,并且您获得seg错误:

 int main() { char *s; char *t;//addition int i = 0; printf("%lu \n", sizeof(s)); s = malloc(sizeof(char) * 2); t = malloc(sizeof(char) * 2);//addition printf("%lu \n", sizeof(s)); /*Why is this working?*/ while (i <= 5) { s[i] = 'l'; i++; } printf("%s \n", s); printf("%lu \n", sizeof(char)); printf("%lu \n", sizeof(s[0])); } 

注意:在我使用的环境中,(Windows 7,NI运行时,调试等)我得到了一个seg-fault,这在某种程度上支持了其他答案中未定义的行为断言。

在我看来,这应该是段错误,因为我试图写的比我分配的更多。 这为何有效?

它不是“有效”; 您的代码调用未定义的行为。 “未定义的行为”并不意味着“您的代码会出现段错误”。 这将是定义的行为。 UB意味着任何事情都会发生。

在这种情况下,你正在踩踏你不拥有的记忆。 这有时会出现段错误,但不要指望它。 C没有“段错误”的概念,它来自您的操作系统。

Segfault是来自操作系统的信号 ,告诉您访问特定的内存区域不属于您的业务。 恰好,您正在访问的内容不会触发操作系统内存管理单元的警报。 有很多方法可以利用它(覆盖函数调用,通过覆盖堆栈值来攻击二进制文件等)。

也可能是您的malloc不分配这2个字节和2个字节的情况。 Malloc调用一个系统调用来分配虚拟内存页面 (可能超过2个字节)。 该系统调用(分别用于Linux和Windows的sbrkVirtualAlloc )告诉操作系统将这些页面映射到您需要的页面,然后保护它们,以便其他人(读取:另一个进程/应用程序)意外地踩到您的内存区域(’原因在于在那种情况下,操作系统会以段错误的方式击中个人。

并且还有其他人提到的未定义的行为。

它看起来像这样:malloc分配比你指定的更多的字节..

当你使用malloc(sizeof(s)* 2); // 8然后while(i <= 36)没问题,但是(i <= 37)已经没有了...

当你使用例如malloc(sizeof(s)* 4); // 16然后while(i <= 7572)没问题,但是(i <= 7573)已经没有..

(我在代码:: blocks中测试过)

太糟糕了,丹尼斯·里奇已经死了,它仍然是一个很大的谜,为什么它就像那样,但只是不要太担心它只需要总是足够你需要和null终止字符串

正如其他人所说,它的命中或错过代码是否会导致生产中的运行时错误,因为边界检查没有内置到C ++中(与Java或C#语言不同)。 代码将在内存检查器下导致错误。

你可能知道Valgrind,所以这是一个留给读者的练习。 在Clang的Address Sanitizer下面也是一样的(我添加了一个printf("malloc: %p \n", s); ):

 $ ./t.exe | /usr/local/bin/asan_symbolize.py malloc: 0x60200000b3b0 ================================================================= ==98557==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000b3b2 at pc 0x1065c4b5b bp 0x7fff5963b810 sp 0x7fff5963b808 WRITE of size 1 at 0x60200000b3b2 thread T0 #0 0x1065c4b5a (/Users/jwalton/./t.exe+0x100000b5a) #1 0x7fff870e27e0 (/usr/lib/system/libdyld.dylib+0x27e0) #2 0x0 0x60200000b3b2 is located 0 bytes to the right of 2-byte region [0x60200000b3b0,0x60200000b3b2) allocated by thread T0 here: #0 0x1065d8cd5 (/usr/local/lib/clang/3.3/lib/darwin//libclang_rt.asan_osx_dynamic.dylib+0xfcd5) #1 0x1065c4971 (/Users/jwalton/./t.exe+0x100000971) #2 0x7fff870e27e0 (/usr/lib/system/libdyld.dylib+0x27e0) #3 0x0 Shadow bytes around the buggy address: 0x1c0400001620: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x1c0400001630: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x1c0400001640: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x1c0400001650: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x1c0400001660: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x1c0400001670: fa fa fa fa fa fa[02]fa fa fa 00 00 fa fa fd fa 0x1c0400001680: fa fa fd fa fa fa 00 00 fa fa fd fa fa fa fd fa 0x1c0400001690: fa fa 00 00 fa fa 00 00 fa fa fd fa fa fa fd fa 0x1c04000016a0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x1c04000016b0: fa fa 00 00 fa fa fd fa fa fa fd fa fa fa 00 00 0x1c04000016c0: fa fa 00 00 fa fa fd fa fa fa fd fa fa fa 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 ASan internal: fe ==98557==ABORTING