 
                            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 pointed-to referenced array object. Adding or subtracting a scaled integer value that is not unitless to or from 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.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 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(arr[0])])idiom, is allowed provided that arr refers to an array and not a pointer.
Noncompliant Code Example
In this noncompliant code example, the pointer sizeof(buf) is added to the array buf. This example is noncompliant because sizeof(buf), which is clearly incorrect because sizeof(buf) has unit bytes is scaled by int and then scaled again when added to buf.
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| enum { INTBUFSIZE = 80 }; extern int getdata(void); int buf[INTBUFSIZE]; void func(void) { int *buf_ptr = buf; while (havedata && 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:
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| enum { INTBUFSIZE = parseint(getdata); } 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, but skip has unit bytes because it contains the result of offsetof skip is scaled by the size of struct big.
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| #include <string.h> #include <stdlib.h> #include <stddef.h> struct big { unsigned long long ull_1a; /* typicallyunsigned 8long bytes */long ull_b; 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 */ }; /* ... */ _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:
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| #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_2b); structunsigned bigchar *sptr = (structunsigned bigchar *)malloc( sizeof(struct big) ); if (!sptr == NULL) { /* Handle malloc() error */ } memset(sptr + skip, 0, sizeof(struct big) - skip); /* ... */ free(sptr); s ptr = 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 bytes are scaled by the size of wchar_t when added to error_msg.:
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| #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) - 1) * sizeof(wchar_t), WCHAR_BUF - 7, stdin); /* ... */ } | 
Exceptions
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: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.
| Code Block | ||
|---|---|---|
| 
 | ||
| 
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
| 
 | |||
| #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 | Detectable | Repairable | Priority | Level | 
|---|---|---|---|---|---|---|
| ARR39-C | High | Probable | No | No | P6 | L2 | 
Automated Detection
| Tool | Version | Checker | Description | ||||||
|---|---|---|---|---|---|---|---|---|---|
| Astrée | 
 | scaled-pointer-arithmetic | Partially checked Besides direct rule violations, Astrée reports all (resulting) out-of-bound array accesses. | ||||||
| Axivion Bauhaus Suite | 
 | CertC-ARR39 | Fully implemented | ||||||
| CodeSonar | 
 | LANG.MEM.BO | Buffer overrun | ||||||
| Coverity | 
 | BAD_SIZEOF 
 | Partially implemented | ||||||
| Cppcheck Premium | 
 | premium-cert-arr39-c | |||||||
| Helix QAC | 
 | DF4955, DF4956, DF4957 | |||||||
| Klocwork | 
 | CERT.ARR.PTR.ARITH | |||||||
| LDRA tool suite | 
 | 47 S, 489 S, 567 S, 64 X, 66 X, 68 X, 69 X, 70 X, 71 X | Partially implemented | ||||||
| Parasoft C/C++test | 
 | CERT_C-ARR39-a | Avoid accessing arrays out of bounds | ||||||
| Polyspace Bug Finder | 
 | Checks for incorrect pointer scaling (rule fully covered). | |||||||
| RuleChecker | 
 | scaled-pointer-arithmetic | Partially checked | ||||||
| TrustInSoft Analyzer | 
 | index_in_address | Exhaustively detects undefined behavior (see one compliant and one non-compliant example). | 
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Key here (explains table format and definitions)
| 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] | 
...
  Wiki Markup