According to the C Standard, subclause 6.7.6.3, paragraph 14 [ISO/IEC 9899:2011],
An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.
Subclause 6.11.6 states that
The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
Consequently, functions that accept no arguments Functions that takes no parameter should explicitly declare a void
parameter as in their parameter list. This holds true during in both the declaration and definition section sections (and they which should match), especially given that many compilers today still allow implicitly declared functions, though C99 has eliminated it.unmigrated-wiki-markup
Defining a function with or without void is not the same, because in latter case the compiler will not check whether the function is called with parameters at all \[[C void usage|http://tigcc.ticalc.org/doc/keywords.html#void]\]. Thus, function calling with arbitrary parameters will be accepted without a warning at compile 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 [TIGCC, void usage]. Consequently, function calling with arbitrary parameters will be accepted without a warning at compile time.
Failure to declare a void
parameter will results result in
- An ambiguous functional interface between the caller and callee
...
- .
- Sensitive information outflow.
There is a similar rule that deals with parameter type in a more general sense: \[[A similar recommendation deals with parameter type in a more general sense: DCL07-C. Include the appropriate type information in function declarators|DCL07-C. Include the appropriate type information in function declarators]\]. Wiki Markup
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.
Noncompliant Code Example (ambiguous interface)
Noncompliant Code Example (Ambiguous Interface)
In this noncompliant code example, the caller calls foo()
with an argument of 3. The caller expects foo()
to accept a single int
argument and to output the argument as part of a longer message. Because In this particular example, caller gives a call to foo with parameter specified as 3. Because function 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 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.It is therefore possible that the caller may not detect the error. In this example, for instance, foo()
might output the value 3 as expected.
Because no function parameter In fact, no parameter specified for a function has the same meaning as an arbitrary paramemtersparameter, which means the caller can feed provide an arbitrary number of parameters arguments to the function. Arbitrary parameter list is useful for system logging purpose, e.g., but not the callee's intention in other situation.
Code Block | ||||
---|---|---|---|---|
| ||||
/* In foo.h */ void foo(); /* In foo.c */ void foo() { int i = 3; printf("i value: %d\n", i); } ... /* In caller.c */ #include "foo.h" foo(3); |
Compliant Solution (
...
Ambiguous Interface)
In this examplecompliant solution, void
is specified explicitly specified as a parameter . in the declaration of foo
's prototype:
Code Block | ||||
---|---|---|---|---|
| ||||
/* In foo.h */ void foo(void); /* compileIn using gcc4.3.3foo.c */ void foo (void) { int i = 3; printf("i value: %d\n", i); } /* In caller.c */ #include "foo.h" foo(3); |
Implementation Details (
...
Ambiguous Interface)
In gcc-4.3.3, when the above When the compliant solution is used and foo(3)
is called, gcc will complain the GCC compiler issues the following diagnostic, which alerts the programmer about the misuse of the function interface.:
Code Block | bgColor | #FFCCCC
---|
error: too many arguments to function âfooâ "foo" |
Noncompliant Code Example (
...
Information Outflow)
Another possible vulnerability is the leak of privileged information. In the above this noncompliant code example, suppose a user with high privilege feed privileges feeds some secret input into to the caller that the caller , then caller will pass the info passes 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 ()
. Because of the way foo()
is defined, we might assume 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 implmentation implementation and copy the value manually and contain it in into a less privileged file.
Code Block | ||||
---|---|---|---|---|
| ||||
/* compileCompile using gcc4.3.3 */ void foo () { /* / * useUse asmassembly code to retrieve i * implicitly from caller * and transfer it to a less privilegeprivileged file. */ } ... /* callerCaller */ foo(i); /* i is fed from user input */ |
Compliant Solution (
...
Information Outflow)
Code Block | ||||
---|---|---|---|---|
| ||||
void foo (void) { int i = 3; printf("i value: %d\n", i); } |
Again, the simple simplest solution is to explicitly specify void
as the only parameter explicitly.
Risk Assessment
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
DCL20-C |
Medium |
Probable |
Low | P12 | L1 |
Automated Detection
Tool | Version | Checker | Description | ||||||
Astrée |
| empty-parameter-list | Fully checked | ||||||
Axivion Bauhaus Suite |
| CertC-DCL20 | |||||||
CodeSonar |
| LANG.FUNCS.PROT | Incomplete function prototype | ||||||
Helix QAC |
| C3001, C3007 | |||||||
Klocwork |
| MISRA.FUNC.NO_PARAMS | |||||||
LDRA tool suite |
| 63 S | Fully Implemented | ||||||
Parasoft C/C++test |
| CERT_C-DCL20-a | The number of arguments passed to a function shall match the number of parameters | ||||||
PC-lint Plus |
| 937 | Partially supported | ||||||
RuleChecker |
| empty-parameter-list | Fully checked | ||||||
SonarQube C/C++ Plugin |
| S929 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
Related Guidelines
In C++, foo()
and foo(void)
have 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 accepts an arbitrary number and type of arguments.
MISRA C:2012 | Rule 8.2 (required) |
Bibliography
[ISO/IEC 9899:2011] | Subclause 6.7.6.3, "Function Declarators (including Prototypes)" Subclause 6.11.6, "Function Declarators" |
[TIGCC, void usage] | Manual, "C Language Keywords": void |
...
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Forward and Section 6.9.1, "Function definitions"
\[[C void usage|http://tigcc.ticalc.org/doc/keywords.html#void]\] Wiki Markup