读取指向函数中的变量时出现分段错误

时间:2018-10-23 15:14:14

标签: c++ c c++11 memory-management bazel

我有以下几段代码:(注意:由于我无法共享数据,所以代码经过简化和更改很多)

exercise.cpp

#include "some_api.h"

extern "C" int extension_init(func_t*, VExtension*);

int main(int argc, char** argv)
{
    VExtension ve;
    extension_init(&func, &ve);
    return 0;
} 

some_api.h

bool func(int const& a, void* const& b, VExtension* const& v)
{
    std::cout << a << b << std::endl;
}

api.h

typedef int (func_t)(int c, void* p, VExtension* v)

file.cpp

#include "api.h" // this is included implicitly

extern "C" int extension_init(func_t* F, VExtension* v)
{
    intptr_t ver = 7;
    F(1, (void*)ver, v);
}

因此,当从F调用funcsome_api.h时,但是在尝试输出值Seg Fault和{{1}时出现a }。 静态分析器给出以下错误消息:

b

1 个答案:

答案 0 :(得分:1)

正确的代码可以工作

如果将func_t使用与func()相同的签名来定义,那么一切都会好起来的,因为从不取消引用b的任意值:

typedef bool (func_t)(int const& a, void* const& b, VExtension* const& v);

请参见demo

但是您的代码不能,所以这里有些混乱

您的代码似乎可以编译,至少从您显示的运行时跟踪来看。但是根据您发布的摘录,代码根本不应该编译。因此,我怀疑您的不同标头在不同的编译单元中使用来自func_t的不同定义来创建危险的混合。如果是这种情况,那么您将处于不确定行为的世界。

例如,返回类型int与返回类型bool不匹配。但更致命的是,在func_t中,参数是纯值,而在func()中,它们都是引用。因此,如果欺骗了编译器,func()的调用者使用的调用约定将与func()的调用约定不兼容,从而导致无效的内存访问(很可能是–但是这将是实现)依赖-生成的调用代码将发送值参数,但是生成的接收代码将期望这些参数是指向值的指针并尝试访问指向的内存位置(这将是无效的)。

其他备注

现在,我不是一名语言律师,但是看到使用C调用约定(extern "C")的函数,以及使用C中不存在的参数和返回类型(例如bool和reference),也很有趣)。

其他见解

使用更正的extension_init定义,在一个编译器上查看func_t的{​​{3}}:

lea rdx, [rsp+8]           ; load effective address of third paramvalue
lea rsi, [rsp+24]          ; load effective address of second param value
mov QWORD PTR [rsp+24], 7  ; initialize value 
lea rdi, [rsp+20]          ; load effective address of first param value
mov DWORD PTR [rsp+20], 1  ; initilize value
call rax

如果为assembly code generated,则生成的代码看起来会不同:

                ; the third value was left out by the global initializer
                ;  but it was previously set with an LEA to load the effective 
                ; address of the struct. 
mov esi, 7      ; pass the second value
mov edi, 1      ; pass the first value
call rax