1

In the C programming language, when you want to declare a function without parameters, you write its signature like this:

int foo(void);

When you want to declare a function with unspecified parameters, its signature looks like this:

int foo();

In this case, it is possible to call the function from another file with parameters chosen by the programmer:

int c = foo(5, 6);

In the upcoming C23 standard, it has been decided that a function signature without parameters will be equivalent to one with void:

int foo();

will be equivalent to

int foo(void);

I was wondering which kind of programming or security issues could this change prevent? (My professor said so but I couldn't think of any) what's the big deal if a funciton isn't expecting parameters and I sent it one parameter? from what I know parameters are saved below saved_ebp

10
  • What if the function expects 3 parameters, but you only provide 2? Or it expects parameters of different type? For a function definition, an empty parameter list already means that it does not take any parameters. Then it seems reasonable to use same semantics for function declaration.
    – Gerhardh
    Commented Jun 13 at 16:28
  • 1
    "from what I know parameters are saved below saved_ebp" That would be true for 1 CPU architecture at most.
    – Gerhardh
    Commented Jun 13 at 16:29
  • 1
    "chosen by the programmer" WRONG: it's chosen by the function implementor. The programmer has to know/match the number and types of the function parameters anyway!!
    – pmg
    Commented Jun 13 at 16:31
  • 1
    If you intentionally provide a function prototype different from the function definition, then you invoke UB. C language knows nothing about saved_ebp or stack. Commented Jun 13 at 16:35
  • 1
    @0___________: Functions may be defined with a prototype and called with a declared type without a prototype or vice-versa, and the behavior is defined by the C standard subject to the specifications in C 2018 6.5.2.2 6 and 7. Commented Jun 13 at 17:20

1 Answer 1

3

The main dangers of these function styles were already removed with C99 when implicit int return types and implicit function declarations were removed from the language. These were some serious hazards as they allowed one to call functions that didn't exist. Or worse, in case the compiler couldn't find a function because you forgot to include a header, the compiler would lie and pretend that it knew about the function, resulting in an incorrect executable with mysterious crashes.

In the current version of C, we have the situation of void func() getting called as func(1,2,3); but a sensible compiler would just discard the arguments not actually used. So the main danger with that would be programmer confusion.

A more concerning problem is function pointers, because a function pointer of type void (*)() is considered compatible with another function pointer such as void (*)(int). This can lead to serious bugs:

#include <stdio.h>

void func(int x)
{
  printf("%d\n", x);
}

int main(void)
{
  void (*fptr)() = func;
  fptr();
}

Here x is uninitialized garbage and this compiles cleanly with gcc 14.1 -std=c17 -Wall -Wextra -pedantic, simply because it is conforming C. This will not compile in C23 since void (*)() will mean void (*)(void), which is not compatible with void (*)(int).

Not the answer you're looking for? Browse other questions tagged or ask your own question.