函数返回地址无效
Overview
同事反馈:调用一个函数,返回地址无效,导致程序崩溃;被调用函数明明分配空间(调用malloc
)成功了,返回后判断是否为NULL也没有用,还是会崩溃了。弄有有点怀疑人生了
代码
代码简化之后,大概是这样:
c
// foo.h文件 -------------------------------------------
#ifndef FOO_H
#define FOO_H
typedef struct {
int a;
int b;
} foo_t;
foo_t* foo(void);
#endif // !FOO_H
// foo.c文件 -------------------------------------------
#include "foo.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
foo_t* foo() {
foo_t* foo = (foo_t*)malloc(sizeof(foo_t));
if (foo == NULL) {
printf("Failed to malloc memory, error msg: %s\n", strerror(errno));
return NULL;
}
memset(foo, 0, sizeof(foo_t));
return foo;
}
// main.c文件 -------------------------------------------
#include <stdio.h>
int main(int argc, char* argv[]) {
// 调用foo函数,返回地址无效
foo_t* bar = foo();
if (bar == NULL) {
printf("bar is NULL\n");
}
// 崩溃
// do something with bar
bar->a = 100;
// other code ...
return 0;
}
调用foo
函数,返回地址无效,判断是否为NULL也拦截不了,操作bar
里面的内容,程序就崩溃了。哪里有问题?
原因
已知
foo
里面的malloc
函数调用成功了,返回了一个有效的地址;但foo
函数完成后,返回的地址就无效了。这是为什么呢?
详细解释
问题在于main.c
中没有包含foo.h
头文件,缺少函数原型定义,编译器在编译的时候不认识这个foo_t*
类型,编译器把它当成int
类型处理了。一个8字节的地址,被当成4字节的int
类型处理了,高4字节数据丢失了,比如:0x00000001 00304080
的地址变成了0x00304080
,但它也不是空,返回一个低位区域的地址,所以返回的地址就无效了。
解决
通过调试定位的问题,用lldb的p
命令,打印malloc
分配的地址,以及函数返回值存放的bar
地址值,发现高4字节数据丢失了
包含对应函数原型的头文件
总结
- 写代码不规范
- 老版本编译器检查不严谨
- 可以尝试开启编译器的
-Werror
选项,开启后,编译器会把警告当成错误,让编译不通过