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

image

问题分析

查看崩溃堆栈:

image

发现内存无法访问。注意返回的str的地址:0xFFFFFFFF8BFDF3C0 ,仅有低8位有值,高8位全是1,大概不正确(也出现过高8位全0的情况,总之就是低8位看起来正常,高8位看起来没赋值)。

进一步检查当前进程的地址空间也能发现,这个 0xFFFFFFFF8BFDF3C0 地址根本不在当前进程空间中:

image

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

image

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

image

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

其实在编译时就能看到出现了警告信息(calloc在libc中,因此函数定义能链接上):

image

解决方案

显式声明 calloc ,即引入 stdlib.h

总结

函数无返回值时默认返回int类型

foo() {
    return 42;
}
// 编译器会假定foo()的返回值类型是int,即相当于:
int foo() {
    return 42;
}

注意:

  • 如果函数声明或定义中没有返回类型,并且该函数包含return语句,且返回值类型与int不兼容,编译器会报错。
  • 在现代C编译器(C99及之后的版本)中,不显式指定返回类型通常会触发警告或错误,建议始终明确指定返回类型。
posted @ 2025-05-07 16:52  3的4次方  阅读(38)  评论(0)    收藏  举报