Skip to content
Published at:

函数返回地址无效

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选项,开启后,编译器会把警告当成错误,让编译不通过

Ref:

Updated at: