在下面的代码段中,str_s不应该指向堆栈中的某个位置。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* fun_s(){
char str[8]="vikash";
printf("s :%p\n", str);
return str;
}
char* fun_h(){
char* str = (char*)malloc(8);
printf("h :%p\n", str);
strcpy(str, "vikash");
return str;
}
int main(){
char* str_s = fun_s();
char* str_h = fun_h();
printf("s :%p\nh :%p\n", str_s, str_h);
return 0;
}我知道fun_s的返回存在问题,并且这个指针的内容不能被信任,但根据我的理解,它应该指向堆栈中的某个位置,而不是零?我在我的控制台中得到以下输出。请你解释一下为什么第三行打印(零)而不是0x7ffce7561220
s :0x7ffce7561220
h :0x55c49538d670
s :(nil)
h :0x55c49538d670GCC版本
gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.操作系统:Ubuntu 18.04.3 LTS
发布于 2019-12-15 12:14:21
编译器是有意从该函数中注入一个空返回值。我没有gcc 7.4,但我有7.3,我想结果是相似的:
将fun_s编译为程序集可提供以下内容:
.LC0:
.string "s :%p\n"
fun_s:
push rbp
mov rbp, rsp
sub rsp, 16
movabs rax, 114844764957046
mov QWORD PTR [rbp-8], rax
lea rax, [rbp-8]
mov rsi, rax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0 ; ======= HERE =========
leave
ret注意,0到eax的硬集合,它将在返回到调用方时保存结果指针。
使str静态提供以下内容:
.LC0:
.string "s :%p\n"
fun_s:
push rbp
mov rbp, rsp
mov esi, OFFSET FLAT:str.2943
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, OFFSET FLAT:str.2943
pop rbp
ret简而言之,编译器正在检测本地地址返回,并将其重写为NULL。在这样做时,它可以防止任何后来恶意使用所述地址(例如:内容注入攻击)。
我认为没有理由不允许编译器这样做。我相信语言纯粹主义者会证实或拒绝这种怀疑。
发布于 2019-12-15 12:10:01
大多数现代编译器检测到指向局部变量的指针的返回,实际上返回NULL (一般来说,对于UBs来说比较激进,其方法是-让程序尽快失败或“使UB能够检测运行时”,就像在本例中那样) https://godbolt.org/z/pDUXmm。
https://stackoverflow.com/questions/59343586
复制相似问题