I have a variadic function in C to write in a log file, but as soon as it is invoked, it gives a segmentation fault in the header.
In the main process, the call has this format:
mqbLog("LOG_INFORMATION",0,0,"Connect",0,"","Parameter received");
and the function is defined this way:
void mqbLog(char *type,
int numContext,
double sec,
char *service,
int sizeData,
char *data,
char *fmt,
...
)
{
//write the log in the archive
}
It compiles OK. When I debug the process, the call to the mqbLog
function is done, and it gives me the segmentation fault in the open bracket of the function, so I can ask about the function values:
(gdb) p type
$1 = 0x40205e "LOG_INFORMATION"
(gdb) p numContext
$2 = 0
(gdb) p sec
$3 = 0
(gdb) p service
$4 = 0x0
(gdb) p sizeData
$5 = 4202649
(gdb) p data
$6 = 0x0
Any ideas will be gratefully received.
Based on the gdb output, it looks like the caller didn't have a prototype for the function it was calling. As @JonathanLeffler noticed, you wrote
0
instead of0.0
, so it's passing an integer where the callee is expecting adouble
.Judging from the pointer value, this is probably on x86-64 Linux with the System V calling convention, where the register assigned for an arg is determined by it being e.g. the third integer arg. (See the x86 wiki for ABI/calling convention docs).
So if the caller and callee disagree about the function signature, they will disagree about which arg goes in which register, which I think explains why gdb is showing args that don't match the caller.
In this case, the caller puts
"Connect"
(the address) in RCX, because it's the 4th integer/pointer arg with that implicit declaration.The caller looks for the value of
service
in RDX, because its caller's 3rd integer/pointer arg.sec
is 0.0 in the callee apparently by chance. It's just using whatever was sitting in XMM0. Or maybe possibly uninitialized stack space, since the caller would have setAL=0
to indicate that no FP args were passed in registers (necessary for variadic functions only). Noteal
= number of fp register args includes the fixed non-variadic args when the prototype is available. Compiling your call with the prototype available includes amov eax, 1
before thecall
. See the source+asm for compiling with/without the prototype on the Godbolt compiler explorer.In a different calling convention (e.g.
-m32
with stack args), things would break at least a badly because those args would be passed on the stack, butint
anddouble
are different sizes.Writing
0.0
for the FP args would make the implicit declaration match the definition. But don't do this, it's still a terrible idea to call undeclared functions. Use-Wall
to have the compiler tell you when your code does bad things.You function might still crash; who knows what other bugs you have in code that's not shown?
When your code crashes, you should look at the asm instruction it crashed on to figure out which pointer was bad — e.g. run
disas
in gdb. Even if you don't understand it yourself, including that in a debugging-help question (along with register values) can help a lot.