Search code examples
glibcfcntlvariadic-functions

why glibc fcntl is implemented as this?


all;I'm looking the glibc source code now;i have a question is this:

int fcntl(int fd, int cmd, ...) {
    va_list ap;
    va_start(ap, cmd);
    void* arg = va_arg(ap, void*);
    va_end(ap);
    return __fcntl64(fd, cmd, arg);
}

why this ???!!!

fcntl(fd,cmd); // is this a trouble?
fcntl(fd,cmd,i/*int type*/); // and this?

Thanks,anyone.


Solution

  • Because it is the most portable way of doing that. The system ABI could (and sometimes does, e.g. x86-64 Linux ABI) define different calling conventions for variadic and for fixed arity functions.

    Probably, older libc versions just defined int fcntl(int fd, int cmd, void*arg) and that usually worked (at least if arg was not used and not accessed when not needed), perhaps on 32 bits x86 with an ABI requiring every argument to be passed on the stack. But on 64 bits x86-64 some arguments are passed by registers (and which ones and how may differ for variadic functions).

    Of course fcntl(2) and open(2) can be called with both two and three arguments.

    If you call fcntl(fd, F_SETLK, &mylock) it should be ok, but if you forgot the third argument with fcntl(fd,F_SETLK) it becomes undefined behavior and you might get some segmentation violation (but probably not). Be very scared of undefined behavior.

    You could compile some sample code with gcc -Wall -O -fverbose-asm -S to get the generated assembler code (look into the emitted .s assembler file with a pager or editor) and figure out, after reading your ABI specification, how calls are really done.