CertC++-ARR39ΒΆ
Do not add or subtract a scaled integer to a pointer
Required inputs: IR
Pointer arithmetic is appropriate only when the pointer argument refers to an array (see ARR37-C. Do not add or subtract an integer to a pointer to a non-array object), including an array of bytes. When performing pointer arithmetic, the size of the value to add to or subtract from a pointer is automatically scaled to the size of the type of the referenced array object. Adding or subtracting a scaled integer value to or from a pointer is invalid because it may yield a pointer that does not point to an element within or one past the end of the array. (See ARR30-C. Do not form or use out-of-bounds pointers or array subscripts.)
Adding a pointer to an array of a type other than character to the result of
the
sizeof operator or
offsetof macro, which returns a size and an offset, respectively,
violates this rule. However, adding an array pointer to the number of array
elements, for example, by using the
arr[sizeof(arr)/sizeof(arr[0])]) idiom, is allowed provided that
arr refers to an array and not a pointer.
Noncompliant Code Example
In this noncompliant code example,
sizeof(buf) is added to the array
buf. This example is noncompliant because
sizeof(buf) is scaled by
int and then scaled again when added to
buf.
enum { INTBUFSIZE = 80 };
extern int getdata(void);
int buf[INTBUFSIZE];
void func(void) {
int *buf_ptr = buf;
while (buf_ptr < (buf + sizeof(buf))) {
*buf_ptr++ = getdata();
}
}
Compliant Solution
This compliant solution uses an unscaled integer to obtain a pointer to the end of the array:
enum { INTBUFSIZE = 80 };
extern int getdata(void);
int buf[INTBUFSIZE];
void func(void) {
int *buf_ptr = buf;
while (buf_ptr < (buf + INTBUFSIZE)) {
*buf_ptr++ = getdata();
}
}
Noncompliant Code Example
In this noncompliant code example,
skip is added to the pointer
s. However,
skip represents the byte offset of
ull_b in
struct big. When added to
s,
skip is scaled by the size of
struct big.
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
struct big {
unsigned long long ull_a;
unsigned long long ull_b;
unsigned long long ull_c;
int si_e;
int si_f;
};
void func(void) {
size_t skip = offsetof(struct big, ull_b);
struct big *s = (struct big *)malloc(sizeof(struct big));
if (s == NULL) {
/* Handle malloc() error */
}
memset(s + skip, 0, sizeof(struct big) - skip);
/* ... */
free(s);
s = NULL;
}
Compliant Solution
This compliant solution uses an
unsigned char * to calculate the offset instead of using a
struct big *, which would result in scaled arithmetic:
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
struct big {
unsigned long long ull_a;
unsigned long long ull_b;
unsigned long long ull_c;
int si_d;
int si_e;
};
void func(void) {
size_t skip = offsetof(struct big, ull_b);
unsigned char *ptr = (unsigned char *)malloc(
sizeof(struct big)
);
if (ptr == NULL) {
/* Handle malloc() error */
}
memset(ptr + skip, 0, sizeof(struct big) - skip);
/* ... */
free(ptr);
ptr = NULL;
}
Noncompliant Code Example
In this noncompliant code example,
wcslen(error_msg) * sizeof(wchar_t) bytes are scaled by the size
of
wchar_t when added to
error_msg:
#include <wchar.h>
#include <stdio.h>
enum { WCHAR_BUF = 128 };
void func(void) {
wchar_t error_msg[WCHAR_BUF];
wcscpy(error_msg, L"Error: ");
fgetws(error_msg + wcslen(error_msg) * sizeof(wchar_t),
WCHAR_BUF - 7, stdin);
/* ... */
}
Compliant Solution
This compliant solution does not scale the length of the string;
wcslen() returns the number of characters and the addition
to
error_msg is scaled:
#include <wchar.h>
#include <stdio.h>
enum { WCHAR_BUF = 128 };
const wchar_t ERROR_PREFIX[7] = L"Error: ";
void func(void) {
const size_t prefix_len = wcslen(ERROR_PREFIX);
wchar_t error_msg[WCHAR_BUF];
wcscpy(error_msg, ERROR_PREFIX);
fgetws(error_msg + prefix_len,
WCHAR_BUF - prefix_len, stdin);
/* ... */
}
Risk Assessment
Failure to understand and properly use pointer arithmetic can allow an attacker to execute arbitrary code.
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| ARR39-C | High | Probable | High | P6 | L2 |
Related Guidelines
| Taxonomy | Taxonomy item | Relationship |
|---|---|---|
| CERT C Secure Coding Standard | ARR30-C. Do not form or use out-of-bounds pointers or array subscripts | Prior to 2018-01-12: CERT: Unspecified Relationship |
| CERT C Secure Coding Standard | ARR37-C. Do not add or subtract an integer to a pointer to a non-array object | Prior to 2018-01-12: CERT: Unspecified Relationship |
| ISO/IEC TR 24772:2013 | Pointer Casting and Pointer Type Changes [HFC] | Prior to 2018-01-12: CERT: Unspecified Relationship |
| ISO/IEC TR 24772:2013 | Pointer Arithmetic [RVG] | Prior to 2018-01-12: CERT: Unspecified Relationship |
| MISRA C:2012 | Rule 18.1 (required) | Prior to 2018-01-12: CERT: Unspecified Relationship |
| MISRA C:2012 | Rule 18.2 (required) | Prior to 2018-01-12: CERT: Unspecified Relationship |
| MISRA C:2012 | Rule 18.3 (required) | Prior to 2018-01-12: CERT: Unspecified Relationship |
| MISRA C:2012 | Rule 18.4 (advisory) | Prior to 2018-01-12: CERT: Unspecified Relationship |
| CWE 2.11 | CWE-468, Incorrect Pointer Scaling | 2017-07-07: CERT: Exact |
Bibliography
| [ Dowd 2006] | Chapter 6, "C Language Issues" |
| [ Murenin 07] |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
scaled_arith |
Do not add or subtract a scaled integer to a pointer. |
None |
False |
Options
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
This rule has no individual options.