Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Dangerous C function with different prototype is possible

Here’s a question that’s pretty special and one I’ve never been aware of before. Apparently I can create a function in C that differs from its function prototype in the passing parameters. The only requirement is that the function must not know the function prototype at compile time.

In my minimal example, I created the following header Test.h:

int Test(int);

I also created the following main.c:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#include <stdio.h>
#include "Test.h"

int main()
{
    int a = Test(5);
    int b = Test(5);
    printf("%d", a);
}

When I use this Test.c, an error occurs when compiling, as expected:

#include <stdio.h>
#include "Test.h"

void Test(void)
{
    printf("HW\n");
}

If I write Test.c like this, the program is compiled, linked and is executable. Of course, the variable a has a seemingly arbitrary value.

#include <stdio.h>

void Test(void)
{
    printf("HW\n");
}

Why can this program be linked and where does the return parameter come from, for example?
This also seems very dangerous if something like this happens accidentally in larger code.

Quick additional info, when I use the same code in a C++ project, there are Linker Errors. So if I use main.cpp and Test.cpp instead of main.c and Test.c. Here things seem to be handled differently with the left. But I would also have been surprised, since C++ has function overloading.

>Solution :

The behavior is undefined, as you have observed.

The reason you do not get an error is the linker has no information about the calling convention used in Test.c and main.c the only information is the symbol name Test and the type of reference (function call).

Here is a possible sequence of events:

  • The main function calls the Test function, which probably behaves as expected: it calls printf which should print HW and a newline, then it returns without a return value.
  • main then retrieves the return value it expects to have been stored in the conventional place where it should have been put by Test, in general, for an int return type, this is a register, and main calls printf
    to print this value.
  • There is a good chance the value printed is 3 because printf returned 3 as an int, thus it stored 3 in the proper register, and Test probably did not change the register between the printf call and its own return statement (no guarantee of that).

You can investigate more by making the compiler produce the assembly source code with -s or -S, or play with Godbolt Compiler Explorer

Compiling the code as C++ does produce an error because unlike C, C++ stores the argument types along with the function names (it constructs synthetic names in a process called mangling) so when you link the main.o object file with the incorrect Test.o, the function names do not match and you get a missing symbol error.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading