-3

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Alan Bry
  • 27
  • 1
  • 7
  • You have a bug in your implementation of that function. I suggest to start by reading the appropriate manuals around ``. – Kerrek SB Dec 20 '16 at 23:06
  • 5
    Give us enough code to replicate the error. – David Schwartz Dec 20 '16 at 23:08
  • 4
    Where's the declaration of the function? Your call relies on the implicit conversion of `0` to `0.0` under the scope of a prototype. Omitting the prototype where the function is called is inherently undefined behaviour; you must *always* have a prototype in scope before calling a variadic function. Your function is crashing, but you've not shown how you've implemented the function. How do you expect us to help you debug it? There are lots of things you could be doing wrong; many of them could lead to a crash. Please include an MCVE ([MCVE]) that reproduces the crash. – Jonathan Leffler Dec 20 '16 at 23:11
  • 1
    You can see that the `sizeData` got misaligned, this looks more like some pointer (`0x402099`). If this function is declared in a different translation unit, my guess is that the declaration does not agree with the definition. Try passing something like `3.14` for `sec` and debugging again. But first, compile your program with all warnings enabled. – The Vee Dec 20 '16 at 23:25
  • @JonathanLeffler: surprisingly, I think there's enough information here to answer the mismatch between caller and callee arg values. (Well spotted with the implicit declaration, I hadn't considered the possibility that the OP left that out. Did you clue in to that from gdb's arg mismatch?) – Peter Cordes Dec 21 '16 at 00:42
  • 1
    @PeterCordes: the problems GDB was having suggested something along those lines. I'd've preferred to get the info from the OP, but your inference is probably correct. – Jonathan Leffler Dec 21 '16 at 02:19

1 Answers1

2

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 of 0.0, so it's passing an integer where the callee is expecting a double.


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 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 set AL=0 to indicate that no FP args were passed in registers (necessary for variadic functions only). Note al = number of fp register args includes the fixed non-variadic args when the prototype is available. Compiling your call with the prototype available includes a mov eax, 1 before the call. 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, but int and double 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.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Thanks Peter! I made the changes you listed and work perfectly (the _double_ number (duh), the function declaration) . Sorry if i couldn't answer before, yesterday was a chaotic day D: – Alan Bry Dec 21 '16 at 14:22