C语言一个内存分配引发的问题——指针长度截断
C语言一个内存分配引发的问题——指针长度截断
问题现象
#include <stdio.h>
#include <string.h>
int main() {
char* str = NULL;
str = (char*)calloc(1, 5);
fprintf(stderr, str);
return 0;
}
执行到第7行时,崩溃。说访问了非法内存 str 。

问题分析
查看崩溃堆栈:

发现内存无法访问。注意返回的str的地址:0xFFFFFFFF8BFDF3C0 ,仅有低8位有值,高8位全是1,大概不正确(也出现过高8位全0的情况,总之就是低8位看起来正常,高8位看起来没赋值)。
进一步检查当前进程的地址空间也能发现,这个 0xFFFFFFFF8BFDF3C0 地址根本不在当前进程空间中:

如果运行时单步调试,查看一下calloc返回值(我是x86_64环境,因此查看rax寄存器):

明显发现这个返回地址的高8位是有值的,但是在执行完 mov 指令后,高8位被丢弃了:

此时问题就明确了,64位的指针赋值到只有32位的变量,导致高32位丢失。从而后续将这个低32位作为指针使用时,自然会出问题。查阅后发现,C语言编译器对于缺少声明的函数,默认认为其返回值是 int ,而我是x86_64环境,指针占8B,int占4B,因此会出现这个问题。
其实在编译时就能看到出现了警告信息(calloc在libc中,因此函数定义能链接上):

解决方案
显式声明 calloc ,即引入 stdlib.h
总结
函数无返回值时默认返回int类型
foo() {
return 42;
}
// 编译器会假定foo()的返回值类型是int,即相当于:
int foo() {
return 42;
}
注意:
- 如果函数声明或定义中没有返回类型,并且该函数包含
return语句,且返回值类型与int不兼容,编译器会报错。 - 在现代C编译器(C99及之后的版本)中,不显式指定返回类型通常会触发警告或错误,建议始终明确指定返回类型。

浙公网安备 33010602011771号