...
UB | Description | |||
---|---|---|---|---|
Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that does not point into, or just beyond, the same array object. | ||||
Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that points just beyond the array object and is used as the operand of a unary | ||||
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="f160d1a66400f114-5ccec913-42624904-aa219fa8-460a1bca400d0faa9aefde39"><ac:plain-text-body><![CDATA[ | [46 | CC. Undefined Behavior#ub_46] | An array subscript is out of range, even if an object is apparently accessible with the given subscript (as in the lvalue expression | ]]></ac:plain-text-body></ac:structured-macro> |
An attempt is made to access, or generate a pointer to just past, a flexible array member of a structure when the referenced object provides no elements for that array. |
...
Code Block | ||
---|---|---|
| ||
static const size_t COLS = 5;
static const size_t ROWS = 7;
static int matrix[ROWS][COLS];
void init_matrix(int x) {
for (size_t i = 0; i != ROWS; ++i)
for (size_t j = 0; j != COLS; ++j)
matrix[i][j] = x;
}
|
Noncompliant Code Example (Pointer Past Flexible Array Member)
In the following noncompliant example the function f
attempts to iterate over the elements of the flexible array member buf
, starting with the second element. However, since function g
does not allocate any storage for the member, the expression first++
in find()
will attempt to form a pointer just past the end of buf
when there are no elements. This attempt results in undefined behavior 59.
Code Block | ||
---|---|---|
| ||
struct S {
size_t len;
char buf[]; /* flexible array member */
};
char* find(const struct S *s, int c) {
char *first = s->buf;
char *last = s->buf + s->len;
while (first++ != last) /* undefined behavior here */
if (*first == (unsigned char)c)
return first;
return NULL;
}
void g() {
struct S *s = (struct S*)malloc(sizeof (struct S));
s->len = 0;
/* ... */
char *where = find(s, '.');
/* ... */
}
|
Compliant Solution
The compliant solution avoids incrementing the pointer unless a value past the end is known to exist.
Code Block | ||
---|---|---|
| ||
struct S {
size_t len;
char buf[]; /* flexible array member */
};
char* find(const struct S *s, int c) {
char *first = s->buf;
char *last = s->buf + s->len;
while (first != last) /* avoid incrementing here */
if (*++first == (unsigned char)c)
return first;
return NULL;
}
void g() {
struct S *s = (struct S*)malloc(sizeof (struct S));
s->len = 0;
/* ... */
char *where = find(s, '.');
/* ... */
}
|
Automated Detection
The Coverity Prevent Version 5.0 ARRAY_VS_SINGLETON checker can detect the access of memory past the end of a memory buffer/array. The NEGATIVE_RETURNS checker can detect when the loop bound may become negative. The OVERRUN_STATIC and OVERRUN_DYNAMIC checker can detect the out of bound read/write to array allocated statically or dynamically.
...