CertC-DCL20ΒΆ
Explicitly specify void when a function accepts no arguments
Required inputs: IR
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 should explicitly declare a
void parameter in their parameter list. This holds true in both
the declaration and definition sections (which should match).
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 [
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 result in
- An ambiguous functional interface between the caller and callee.
- Sensitive information outflow.
A similar recommendation deals with parameter type in a more general sense: DCL07-C. Include the appropriate type information in function declarators.
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
foo() is declared without the
void parameter, the compiler will not perform any caller check. 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 has the same meaning as an arbitrary parameter, the caller can provide an arbitrary number of arguments to the function.
/* 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 compliant solution,
void is specified explicitly as a parameter in the declaration of
foo's prototype:
/* In foo.h */
void foo(void);
/* In foo.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)
When the compliant solution is used and
foo(3) is called, the GCC compiler issues 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
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 implementation and copy
the value manually into a less privileged file.
/* Compile using gcc4.3.3 */
void foo() {
/*
* Use assembly code to retrieve i
* implicitly from caller
* and transfer it to a less privileged 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 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 |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
parameterless_func_without_void_param |
Function with no parameters shall be declared with (void) |
None |
False |
Options
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
This rule has no individual options.