ARR39-C. Do not add or subtract a scaled integer to a pointer
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 | Detectable | Repairable | Priority | Level |
|---|---|---|---|---|---|---|
| ARR39-C | High | Probable | No | No | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description |
|---|---|---|---|
| Astrée | 25.10 | scaled-pointer-arithmetic | Partially checked Besides direct rule violations, Astrée reports all (resulting) out-of-bound array accesses. |
| Axivion Bauhaus Suite | 7.2.0 | CertC-ARR39 | Fully implemented |
| CodeSonar | 9.1p0 | LANG.MEM.BO | Buffer overrun |
| Coverity | 2017.07 | BAD_SIZEOF | Partially implemented |
| Cppcheck Premium | 24.11.0 | premium-cert-arr39-c | |
| Helix QAC | 2025.2 | DF4955, DF4956, DF4957 | |
| Klocwork | 2025.2 | CERT.ARR.PTR.ARITH | |
| LDRA tool suite | 9.7.1 | 47 S, 489 S, 567 S, 64 X, 66 X, 68 X, 69 X, 70 X, 71 X | Partially implemented |
| Parasoft C/C++test | 2025.2 | CERT_C-ARR39-a | Avoid accessing arrays out of bounds |
| Polyspace Bug Finder | R2025b | Checks for incorrect pointer scaling (rule fully covered). | |
| RuleChecker | 25.10 | scaled-pointer-arithmetic | Partially checked |
| TrustInSoft Analyzer | 1.38 | 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 ] |


