C - Variadic 函数编译但给出分段错误

C - Variadic function compiles but gives segmentation fault

我在 C 中有一个可变参数函数可以写入日志文件,但是一旦调用它,它就会在 header.

中给出一个分段错误

在主进程中,调用格式如下:

mqbLog("LOG_INFORMATION",0,0,"Connect",0,"","Parameter received");  

函数是这样定义的:

void mqbLog(char *type,
            int  numContext,
            double sec,
            char *service,
            int   sizeData,
            char *data,
            char *fmt,
            ...
            )
{  
    //write the log in the archive
}

编译成功。当我调试过程时,对 mqbLog 函数的调用完成了,它在函数的左括号中给出了分段错误,所以我可以询问函数值:

(gdb) p type
 = 0x40205e "LOG_INFORMATION"
(gdb) p numContext
 = 0
(gdb) p sec
 = 0
(gdb) p service
 = 0x0
(gdb) p sizeData
 = 4202649
(gdb) p data
 = 0x0

如有任何想法,我们将不胜感激。

根据 gdb 的输出,调用者似乎没有所调用函数的原型。正如@JonathanLeffler 所注意到的,您写的是 0 而不是 0.0,因此它传递了一个整数,被调用方期望 double.


从指针值判断,这可能是在 x86-64 Linux 上使用 System V 调用约定,其中分配给 arg 的寄存器由它决定,例如第三个 整数 参数。 (请参阅 维基以获取 ABI/calling 公约文档)。

因此,如果调用者和被调用者不同意函数签名,他们将不同意哪个 arg 进入哪个寄存器,我认为这解释了为什么 gdb 显示与调用者不匹配的 args。


在这种情况下,调用者将 "Connect"(地址)放入 RCX,因为它是具有该隐式声明的第 4 个 integer/pointer arg。

调用者在 RDX 中查找 service 的值,因为其调用者的第 3 个 integer/pointer arg.

sec 在被调用者中显然是 0.0 是偶然的。它只是使用 XMM0 中的任何内容。或者可能 可能 未初始化的堆栈 space,因为调用者会设置 AL=0 以指示没有 FP args 被传递到寄存器中(仅可变参数函数需要)。注意 al = 当原型可用时,fp 寄存器参数的数量包括固定的非可变参数。使用 编译您的调用 可用原型包括 call 之前的 mov eax, 1。参见 source+asm 编译 with/without 原型 on the Godbolt compiler explorer.

在不同的调用约定中(例如 -m32 与堆栈参数),事情至少会严重中断,因为这些参数将在堆栈上传递,但是 intdouble 尺寸不同。


为 FP args 编写 0.0 将使隐式声明与定义匹配。 但是不要这样做,调用未声明的函数仍然是一个糟糕的主意。使用 -Wall 让编译器在你的代码做坏事时告诉你。

您的功能可能仍会崩溃;谁知道您在未显示的代码中还有哪些其他错误?


当你的代码崩溃时,你应该查看它崩溃的 asm 指令,以确定哪个指针是坏的——例如运行 disas 在 gdb 中。即使您自己不理解,将其包含在调试帮助问题中(以及寄存器值)也会有很大帮助。