这是我的代码。
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]));
}
在我看来,这应该是段错误,因为我试图写的比我分配的多。为什么这有效?
答案 0 :(得分:6)
在我看来,这应该是段错误,因为我试图写的比我分配的多。为什么这有效?
这不是“有效”;您的代码调用未定义的行为。 “未定义的行为”并不意味着“您的代码会出现段错误”。这将是定义的行为。 UB意味着任何事情都会发生。
在这种情况下,你正在踩踏你不拥有的记忆。这有时会出现段错误,但不要指望它。 C没有“段错误”的概念,它来自你的操作系统。
答案 1 :(得分:3)
Segfault是来自操作系统的信号,告诉您访问特定的内存区域不属于您的业务。恰好,您正在访问的内容不会触发操作系统内存管理单元的警报。有很多方法可以利用它(覆盖函数调用,通过覆盖堆栈值来攻击二进制文件等)。
也可能是您的malloc不分配这2个字节和2个字节。 Malloc调用分配虚拟内存页的系统调用(可能超过2个字节)。系统调用(分别用于Linux和Windows的sbrk
和VirtualAlloc
)告诉操作系统将这些页面映射到您需要的页面,然后保护它们以便其他人(阅读:另一个进程/应用程序)意外地进行操作在你的内存区域(因为在这种情况下操作系统会点击 一个人的头部有一个段错误。)
还有其他人提到的未定义行为。
答案 2 :(得分:2)
插图 (并完全同意)@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,这有点支持其他答案中未定义的行为断言。
答案 3 :(得分:1)
它看起来像这样:malloc分配比你指定的更多的字节..
当你使用malloc(sizeof(s)* 2)时; // 8 然后虽然(i <= 36)是好的,但是虽然(i <= 37)已经没有..
当你使用例如malloc(sizeof(s)* 4)时; // 16 然后虽然(i <= 7572)没问题,但是(i <= 7573)已经没有了..
(我在code :: blocks中测试过)
丹尼斯·里奇已经死了太糟糕了,为什么会这样,这仍然是个大谜 但是,只是不要太担心它只是分配总是足够的 你需要和null终止字符串
答案 4 :(得分:0)
正如其他人所说,它的命中或错过代码是否会导致生产中的运行时错误,因为边界检查没有内置到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