When performing pointer arithmetic, the size of the value to add to a pointer is automatically scaled to the size of the type of the pointed-to object. Adding a value that is not unitless to a pointer shall be diagnosed (subject to exceptions below) because this can result in undefined and unexpected behavior. For example, the sizeof operators and offsetof macro return a value with unit bytes, the function strlen()} returns a value that is unitless, and the function wcslen() returns a value that is unitless.
A common mistake is to add the size of an array to the array itself (i.e. arrsizeof(arr) or arr + sizeof(arr)). One correct idiom is to divide the size of the array by the size of the first element in the array, yielding a value that is unitless (i.e., arr[sizeof(arr)/sizeof(arr0)]).
Noncompliant Code Example
In this noncompliant code example, the pointer buf is added to sizeof(buf), which is clearly incorrect because sizeof(buf) has unit bytes.
int buf[INTBUFSIZE];
int *buf_ptr = buf;
while (havedata && buf_ptr < (buf + sizeof(buf))) {
*buf_ptr++ = parseint(getdata);
}
Noncompliant Code Example
In this noncompliant code example, skip is added to the pointer s, but skip has unit bytes because it contains the result of offsetof.
struct big {
unsigned long long ull_1; /* typically 8 bytes */
unsigned long long ull_2; /* typically 8 bytes */
unsigned long long ull_3; /* typically 8 bytes */
int si_4; /* typically 4 bytes */
int si_5; /* typically 4 bytes */
};
/* ... */
size_t skip = offsetof(struct big, ull_2); struct big *s = (struct big *)malloc(sizeof(struct big)); if (!s) {
/* Handle malloc error */
}
memset(s + skip, 0, sizeof(struct big) - skip);
/* ... */
free(s);
s = NULL;
Noncompliant Code Example
In this noncompliant code example, (wcslen(error_msg) - 1) * sizeof(wchar_t) has unit bytes and is added to the pointer error_msg.
/* ... */ wchar_t error_msg[WCHAR_BUF]; wcscpy(error_msg, "Error: "); fgetws(error_msg + (wcslen(error_msg) - 1) * sizeof(wchar_t), WCHAR_BUF - 7, stdin); /* ... */
Exceptions
EXP408-EX1: Adding a value that is not unitless to a pointer that points to an object that has size 1 need not be diagnosed because this will likely produce the correct result. The following example shows an acceptable use of this exception because (char *)s0 has size 1.
struct big {
unsigned long long ull_1; /* typically 8 bytes */
unsigned long long ull_2; /* typically 8 bytes */
unsigned long long ull_3; /* typically 8 bytes */
int si_4; /* typically 4 bytes */
int si_5; /* typically 4 bytes */
};
/* ... */
size_t skip = offsetof(struct big, ull_2); struct big *s = (struct big *)malloc(sizeof(struct big)); if (!s) {
/* Handle malloc() error */
}
memset((char *)s + skip, 0, sizeof(struct big) - skip);
/* ... */
free(s);
s = NULL;
Bibliography
[[Dowd 06]] Chapter 6, "C Language Issues"
[[ISO/IEC PDTR 24772]] "HFC Pointer casting and pointer type changes" and "RVG Pointer Arithmetic"
[[MISRA 04]] Rules 17.1-17.4
[[MITRE 07]] CWE ID 468
, "Incorrect Pointer Scaling"
[[Murenin 07]]