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 perform checks on the number and type of arguments being passed to the function.
Wiki Markup |
---|
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()
)
Wiki Markup |
---|
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. |
Code Block | ||
---|---|---|
| ||
char *p = malloc(10); |
Compliant Solution: (malloc()
)
Including stdlib.h
ensures the function prototype for malloc()
is declared.
Code Block | ||
---|---|---|
| ||
#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.
Code Block | ||
---|---|---|
| ||
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.
Code Block | ||
---|---|---|
| ||
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.
Code Block | ||
---|---|---|
| ||
func(1, 2); /* ... */ int func(int one, int two, int three){ printf("%d %d %d", one, two, three); return 1; } |
Wiki Markup |
---|
C99 eliminated implicit function declarations from the C language \[[ISO/IEC 9899-1999:TC2|AA. C References#ISO/IEC 9899-1999TC2]\]. However, many compilers 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.
Code Block | ||
---|---|---|
| ||
int func(int, int, int); /* ... */ func(1, 2); /* ... */ int func(int one, int two, int three){ printf("%d %d %d", one, two, three); return 1; } |
Non-Compliant Code Example: (function pointers)
Wiki Markup |
---|
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 \[[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.
Code Block | ||
---|---|---|
| ||
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.
Code Block | ||
---|---|---|
| ||
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 |
---|---|---|---|---|---|
DCL31-C | 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
Wiki Markup |
---|
\[[ISO/IEC 9899-1999:TC2|AA. C References#ISO/IEC 9899-1999TC2]\] Forward, Section 6.9.1, "Function definitions" \[[Spinellis 06|AA. C References#Spinellis 06]\] Section 2.6.1, "Incorrect Routine or Arguments" |