Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

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.

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.

Code Block
bgColor#FFCCCC
langc
/* In foo.h */
void foo();

/* compileIn using gcc4.3.3foo.c */
void foo () {
    int i = 3;
    printf("i value: %d\n", i);
}

...

/* In caller.c */
    #include "foo.h"

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)

In this compliant solution, void is specified explicitly as a parameter in the declaration of foo's prototype:

...

Code Block
bgColor#ccccff
langc
/* 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 this example, void is explicitly specified as a parameter. If the caller calls foo(3) again, a warning message will be issued as follows:

/* 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:

Code Block
Code Block
bgColor#FFCCCC

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.

"€˜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.

...

Code Block
bgColor#FFCCCC
langc

/* 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
bgColor#ccccff
langc

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

Medium

probable

Probable

low

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

Automated Detection

Tool

Version

Checker

Description

Astrée
Include Page
Astrée_V
Astrée_V
empty-parameter-listFully checked
Axivion Bauhaus Suite
Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V
CertC-DCL20
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V
LANG.FUNCS.PROTIncomplete function prototype
Helix QAC
Include Page
Helix QAC_V
Helix QAC_V
C3001, C3007
Klocwork
Include Page
Klocwork_V
Klocwork_V
MISRA.FUNC.NO_PARAMS
LDRA tool suite 
Include Page
LDRA_V
LDRA_V
63 SFully Implemented
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_C-DCL20-a

The number of arguments passed to a function shall match the number of parameters
PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

937

Partially supported

RuleChecker
Include Page
RuleChecker_V
RuleChecker_V
empty-parameter-listFully checked
SonarQube C/C++ Plugin
 
Include Page
SonarQube C/C++ Plugin_V
SonarQube C/C++ Plugin_V
 S929

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

In C++, In C++ the usage of foo() and foo(void) has have exactly the same meaning and effect, so this rule doesn't apply to C++.
But it is still recommended to explicitly declare However, foo(void) should be declared explicitly instead of foo() to distinguish it from foo(...), which will then takes arbitrary parameters.

References

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


...

Image Added Image Added Image Added Wiki Markup\[[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]\]