Functions that take no parameters should explicitly declare a void parameter in their parameter list. This holds true in both the declaration and definition sections (which should match). Many compilers today still allow implicitly declared functions, even though C99 has eliminated them.
Defining a function with a void argument list differs from declaring it with no arguments because in the latter case, the compiler will not check whether the function is called with parameters at all [C void usage]. Consequently, function calling with arbitrary parameters will be accepted without a warning at compile time.
Failure to declare a void parameter will result in
- an ambiguous functional interface between the caller and callee
- sensitive information outflow
A similar rule deals with parameter type in a more general sense: DCL07-C. Include the appropriate type information in function declarators.
In C+, the usage of foo()
and foo(void)
has exactly the same meaning and effect, so this rule doesn't apply to C+. However, foo(void)
should be declared explicitly instead of foo()
to distinguish it from foo(...)
, which will then take arbitrary parameters.
Noncompliant Code Example (Ambiguous Interface)
In this noncompliant code example, the caller calls foo
with a parameter of 3. Because foo()
is declared without the void
parameter, the compiler will not perform any caller check. Due to the accidental internal implementation, the function foo()
outputs the value 3, which matches the caller's expectation. In an inherited code base where foo and the caller are developed at different times, the caller will expect foo()
to accept one integer as a parameter and to output the corresponding message when the parameter is changed.
Because no function parameter has the same meaning as an arbitrary parameter, the caller can feed an arbitrary number of parameters to the function.
void foo() { int i = 3; printf("i value: %d\n", i); } ... /* caller */ foo(3);
Compliant Solution (Ambiguous Interface)
In this compliant solution, void
is specified explicitly as a parameter.
/* compile using gcc4.3.3 */ void foo (void) { int i = 3; printf("i value: %d\n", i); }
Implementation Details (Ambiguous Interface)
When the above compliant solution is used and foo(3)
is called, the GCC compiler will issue the following diagnostic, which alerts the programmer about the misuse of the function interface.
error: too many arguments to function âfooâ
Noncompliant Code Example (Information Outflow)
Another possible vulnerability is the leak of privileged information. In this noncompliant code example, a user with high privileges feeds some secret input to the caller that the caller then passes to foo()
. Because of the way function foo()
is defined, we might assume that there is no way for foo()
to retrieve information from the caller. However, because the value of i
is really passed into a stack (before the return address of the caller), a malicious programmer can change the internal implementation and copy the value manually into a less privileged file.
/* compile using gcc4.3.3 */ void foo() { /* use asm code to retrieve i * implicitly from caller * and transfer it to a less privilege file */ } ... /* caller */ foo(i); /* i is fed from user input */
Compliant Solution (Information Outflow)
void foo(void) { int i = 3; printf("i value: %d\n", i); }
Again, the simplest solution is to explicitly specify void
as the only parameter.
Risk Assessment
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
DCL20-C |
medium |
probable |
low |
P12 |
L1 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[[ISO/IEC 9899:1999]] Forward and Section 6.9.1, "Function definitions"
[C void usage]