zoukankan      html  css  js  c++  java
  • 64位平台上,函数返回指针时遇到的段错误问题

    平台: x86_64

    GCC:  7.3

    类型 长度
    int 4字节
    int * 8字节

    有如下两个文件:

    b.c:

    #include <stdio.h>
    
    static int var = 0x5;
    
    int *func(void)
    {
            printf("var: %d, &var: %p
    ", var, &var);
            return &var;
    }

    a.c:

    #include <stdio.h>
    
    int main(int argc, const char *argv[])
    {
            int *ret = NULL;
    
            ret = func();
            printf("*ret: %d
    ", *ret);
    
            return 0;
    }

    然后编译运行:

    gcc a.c b.c
    
    ./a.out 
    var: 5, &var: 0x55ac51c53010
    Segmentation fault (core dumped)

    可以看到,在访问返回的地址时发生了段错误,第一感觉不应该啊,b.c里定义的是static变量,并不是局部变量啊。那么我们把返回的指针具体数值打印出来,看跟b.c中打印的是否一致,修改a.c如下:

    #include <stdio.h>
    
    int main(int argc, const char *argv[])
    {
            int *ret = NULL;
    
            ret = func();
            printf("ret: %p
    ", ret);
    
            return 0;
    }

    运行如下:

    var: 5, &var: 0x56282a30b010
    ret: 0x2a30b010

    可以看到,二者果然不同,ret的值仅仅是&var的低4字节的内容。

    经过Google,发现,原来是没有在a.c中对func()进行声明,如果没有对func声明,GCC会默认认为func返回的是int类型,而x86_64上,指针占用8个字节,int类型仅仅占用4个字节,所以在赋值时只会把&val的低4字节赋值给ret。

    可以参考:

    https://stackoverflow.com/questions/23144151/64-bit-function-returns-32-bit-pointer

    https://stackoverflow.com/questions/14589314/segmentation-fault-while-accessing-the-return-address-from-a-c-function-in-64-bi

    修改如下,在a.c中增加对func的声明,告诉编译器func的返回值是一个指针类型,需要占用8个字节长度

    #include <stdio.h>
    
    extern int *func(void);
    
    int main(int argc, const char *argv[])
    {
            int *ret = NULL;
    
            ret = func();
            printf("ret: %p, *ret: %d
    ", ret, *ret);
    
            return 0;
    }

    输出:

    var: 5, &var: 0x561cb45bd010
    ret: 0x561cb45bd010, *ret: 5

    与此类似的还有一种:

    .
    ├── a.c
    ├── b.c
    ├── common.h

    common.h:

    #ifndef __ABC_H__
    #define __ABC_H__
    
    struct ABC {
            int a;
            int b;
            int c;
    };
    
    #endif

    b.c:

    #include "common.h"
    
    static struct ABC abc = {
            1, 2, 3
    };
    
    struct ABC *func(void)
    {
            return &abc;
    }

    a.c:

    #include <stdio.h>
    
    extern struct ABC *func(void);
    
    int main(int argc, const char *argv[])
    {
            int *ret = NULL;
    
            struct ABC *abc = func();
            printf("abc: %p
    ", abc);
    
            return 0;
    }

    编译运行:

    gcc a.c b.c
    
    ./a.out      
    abc: 0x55ed86710010

    没有问题,但是如果在a.c中去访问结构体成员的话,编译就会失败:

    gcc a.c b.c      
    a.c: In function ‘main’:
    a.c:12:36: error: dereferencing pointer to incomplete type ‘struct ABC’
      printf("a: %d, b: %d, c:%d
    ", abc->a, abc->b, abc->c);

    原因是,在x86_64上,不管是什么类型的指针,GCC都会会分配8个字节,这个不会有问题,但是如果要访问指针指向的结构体成员的话,就需要告诉GCC这个成员具体是什么样子。解决办法同时是需要声明一下结构体类型,这里包含对应的头文件即可。

    #include <stdio.h>
    #include "common.h"
    
    extern struct ABC *func(void);
    
    int main(int argc, const char *argv[])
    {
            int *ret = NULL;
    
            struct ABC *abc = func();
            printf("abc: %p
    ", abc);
    
            printf("a: %d, b: %d, c:%d
    ", abc->a, abc->b, abc->c);
    
            return 0;
    }

    运行:

    ./a.out 
    abc: 0x55f63c054010
    a: 1, b: 2, c:3

  • 相关阅读:
    POJ1741
    聪聪可可
    [USACO07NOV]Cow Relays
    Android 程序的反破解技术
    在Android上实现SSL握手(客户端需要密钥和证书),实现服务器和客户端之间Socket交互
    vmware中的bridge、nat、host-only的区别
    史上最易懂的Android jni开发资料--NDK环境搭建
    使用javah生成.h文件, 出现无法访问android.app,Activity的错误的解决
    Android apk反编译基础(apktoos)图文教程
    Smali文件语法解析
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/9725151.html
Copyright © 2011-2022 走看看