Function declarators must be declared with the appropriate type information, including a return type, parameter list, and function prototype (if the declarator is part of a function definition). If type information is not properly specified in a function declarator, the compiler cannot properly check function type information.
Attempting to compile a program with a function declarator that does not include the appropriate type information typically generates a warning. These warnings should be resolved [[MSC00-A. Compile cleanly at high warning levels]], but do not prevent program compilation.
Non-Compliant Code Example (malloc()
)
The following example is based on rule [[MEM02-A. Do not cast the return value from malloc()]]. The header file stdlib.h
contains the function prototype for malloc()
. Failing to include stdlib.h
causes malloc()
to be improperly defined.
char *p = malloc(10);
Compliant Solution: (malloc()
)
Including stdlib.h
ensures the function prototype for malloc()
is declared and in scope.
#include <stdlib.h> /* ... */ char *p = malloc(10);
Non-Compliant Code Example: (non-prototype-format declarators)
The non-compliant code example uses the identifier-list form for the parameter declarations.
extern int max(a, b) int a, b; { return a > b ? a : b; }
Section 6.11 of the C99 standards, "Future language directions", states that "The use of function definitions with separate parameter identifier and declaration lists (not prototype-format parameter type and identifier declarators) is an obsolescent feature."
Compliant Solution: (non-prototype-format declarators)
In this compliant solution, extern
is the storage-class specifier and int
is the type specifier; max(int a, int b)
is the function declarator; and the block within {} is the function body.
extern int max(int a, int b) { return a > b ? a : b; }
Non-Compliant Code Example: (function prototypes)
Failure to specify function prototypes results in a function being implicitly defined. Without a function prototype, the compiler assumes the the correct number and type of parameters have been supplied to a function. This can result in unintended and undefined behavior.
In this non-compliant code example, the definition of func()
expects three parameters but is supplied only two. However, because there is no prototype for func()
, the compiler assumes that the correct number of arguments has been supplied, and uses the next value on the program stack as the missing third argument.
func(1, 2); /* ... */ int func(int one, int two, int three){ printf("%d %d %d", one, two, three); return 1; }
C99 eliminated implicit function declarations from the C language [[ISO/IEC 9899-1999:TC2]]. However, compilers will allow compilation of programs containing implicitly defined functions, although they may issue a warning message. These warnings should be resolved [[MSC00-A. Compile cleanly at high warning levels]], but do not prevent program compilation.
Compliant Solution: (function prototypes)
To correct this example, the appropriate function prototype for func()
should be specified.
int func(int, int, int); /* ... */ func(1, 2, 3); /* ... */ int func(int one, int two, int three){ printf("%d %d %d", one, two, three); return 1; }
Non-Compliant Code Example: (function pointers)
If a function pointer is set to refer to an incompatible function , invoking that function via the pointer may cause unexpected data to be taken from the process stack. As a result, unexpected data may be accessed by the called function. This example also violates rule [[DCL35-C. Do not convert a function pointer to a function of an incompatible type]].
In this example, the function pointer fn_ptr
is set to refer to the function add()
, which accepts three integer arguments. However, fn_ptr
is specified to accept two integer arguments. Setting fn_ptr
to refer to add()
results in an unexpected program behavior.
int add(int x, int y, int z) { return x + y + z; } int main(int argc, char *argv[]) { int (*fn_ptr) (int, int); int res; fn_ptr = add; res = fn_ptr(2, 3); /* incorrect */ /* ... */ return 0; }
Compliant Solution: (function pointers)
To correct this example, the declaration of fn_ptr
is changed to accept three arguments.
int add(int x, int y, int z) { return x + y + z; } int main(int argc, char *argv[]) { int (*fn_ptr) (int, int, int) ; int res; fn_ptr = add; res = fn_ptr(2, 3, 4); /* ... */ return 0; }
Risk Assessment
Failing to include type information for function declarators can result in unexpected or unintended program behavior.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
DCL07-A |
1 (low) |
1 (unlikely) |
3 (low) |
P3 |
L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[[ISO/IEC 9899-1999]] Forward, Section 6.9.1, "Function definitions"
[[Spinellis 06]] Section 2.6.1, "Incorrect Routine or Arguments"