Functions that takes no parameter should explicitly declare a void parameter as parameter list. This holds true during both the declaration and definition section (and they should match), especially given that many compilers today still allow implicitly declared functions though C99 has eliminated it.
Failure to declare void parameter will results in ambiguous functional interface between caller and callee, and even sensitive information outflow.
Noncompliant Code Example (ambiguous interface)
/* compile using gcc4.3.3 */ void foo () { int i = 3; printf("i value: %d\n", i); } ... /* caller */ foo(3);
In this particular example, caller gives a call to foo with parameter specified as 3. When compiled with gcc-4.3.3 in Linux, no warning will be issued. Due to the accidental internal implementation, the function foo() outputs i value: 3 which matches with caller's temptation. In an inherited code base where foo and caller are developed at different time, this leads to caller's belief that foo actually accept one integer as parameter and foo will output the corresponding message when parameter is changed.
In fact, no parameter specified for a function has the same meaning as arbitrary paramemters, which means the caller can feed arbitrary number of parameters to the function. Arbitrary parameter list is useful for system logging purpose, e.g., but not the callee's intention in other situation.
Compliant Solution (ambiguous interface)
/* compile using gcc4.3.3 */ void foo (void) { int i = 3; printf("i value: %d\n", i); }
In this example, void is explicitly specified as a parameter. If the caller calls foo(3) again, a warning message will be issued as follows:
error: too many arguments to function âfooâ
Because it is an error message, the programmer can not ignore it and thus previous belief regarding the interface can be rectified.
Noncompliant Code Example (information outflow)
/* 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 */
Another possible vulnerability is the leak of privileged information. In the above example, suppose a user with high privilege feed some secret input into the caller, then caller will pass the info to foo. When doing static code analysis of foo interface, because no parameter is specified, it is easy to assume there's no way that foo can retrieve info from caller. However, because the value of i is really passed into stack (before the return address of caller), a malicious programmer can change the internal implmentation and copy the value manually and contain it in a less privileged file.
Compliant Solution (information outflow)
void foo (void) { int i = 3; printf("i value: %d\n", i); }
Again, the simple solution is to specify void as the only parameter explicitly.
Risk Assessment
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
DCL20-C |
medium |
probable |
low |
P12 |
L1 |
Related Vulnerabilities
There is a similar rule that deals with parameter type in a more general sense: DCL07-C. Include the appropriate type information in function declarators
Other Languages
In C++ the usage of foo() and foo(void) has exactly the same meaning and effect, so this rule doesn't apply to C++. But it is still recommended to explicitly declare foo(void) instead of foo() to distinguish from foo(...), which will then takes arbitrary parameters.