Using type definitions (typedef) can often improve code readability. However, type definitions to pointer types can make it more difficult to write const-correct code because the const qualifier will be applied to the pointer type, not to the underlying declared type.
The following type definition improves readability at the expense of introducing a const-correctness issue. In this example, the const qualifier applies to the typedef instead of to the underlying object type. Consequently, func does not take a pointer to a const struct obj but instead takes a const pointer to a struct obj.
struct obj {
int i;
float f;
};
typedef struct obj *ObjectPtr;
void func(const ObjectPtr o) {
/* Can actually modify o's contents, against expectations */
} |
This compliant solution makes use of type definitions but does not declare a pointer type and so cannot be used in a const-incorrect manner:
struct obj {
int i;
float f;
};
typedef struct obj Object;
void func(const Object *o) {
/* Cannot modify o's contents */
} |
The Win32 SDK headers make use of type definitions for most of the types involved in Win32 APIs, but this noncompliant code example demonstrates a const-correctness bug:
#include <Windows.h>
/* typedef char *LPSTR; */
void func(const LPSTR str) {
/* Can mutate str's contents, against expectations */
} |
This compliant solution demonstrates a common naming convention found in the Win32 APIs, using the proper const type:
#include <Windows.h>
/* typedef const char *LPCSTR; */
void func(LPCSTR str) {
/* Cannot modify str's contents */
} |
Note that many structures in the Win32 API are declared with pointer type definitions but not pointer-to-const type definitions (LPPOINT, LPSIZE, and others). In these cases, it is suggested that you create your own type definition from the base structure type.
#include <Windows.h>
/*
typedef struct tagPOINT {
long x, y;
} POINT, *LPPOINT;
*/
void func(const LPPOINT pt) {
/* Can modify pt's contents, against expectations */
} |
#include <Windows.h>
/*
typedef struct tagPOINT {
long x, y;
} POINT, *LPPOINT;
*/
typedef const POINT *LPCPOINT;
void func(LPCPOINT pt) {
/* Cannot modify pt's contents */
} |
In this noncompliant code example, the declaration of the signal() function is difficult to read and comprehend:
void (*signal(int, void (*)(int)))(int); |
This compliant solution makes use of type definitions to specify the same type as in the noncompliant code example:
typedef void SighandlerType(int signum); extern SighandlerType *signal( int signum, SighandlerType *handler ); |
Function pointer types are an exception to this recommendation.
Code readability is important for discovering and eliminating vulnerabilities.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
DCL05-C | Low | Unlikely | Medium | P2 | L3 |
Tool | Version | Checker | Description |
|---|---|---|---|
| CodeSonar | LANG.STRUCT.PIT | Pointer type inside typedef | |
| Compass/ROSE | |||
| LDRA tool suite | 299 S | Partially implemented | |
| Parasoft C/C++test | MISRA2004-16_7_b | Fully implemented | |
| PRQA QA-C | 5004 | Fully implemented |
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
| SEI CERT C Coding Standard | DCL12-C. Implement abstract data types using opaque types |
| SEI CERT C++ Coding Standard | VOID DCL05-CPP. Use typedefs to improve code readability |