...
UB | Description | Example Code | |||
---|---|---|---|---|---|
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="91cd72fef60e4f03-1e93568e-4fd04253-804da494-3d6efc4f629ac1f9a083c268"><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 | [#Apparently Accessible Out Of Range Index] | ]]></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. | |||||
The pointer passed to a library function array parameter does not have a value such that all address computations and object accesses are valid. |
Anchor | ||||
---|---|---|---|---|
|
...
In the following noncompliant example the function f
find()
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) /* 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, '.');
/* ... */
}
|
Anchor | ||||
---|---|---|---|---|
|
Noncompliant Code Example (Invalid Access By Library Function)
In the following noncompliant example the function f()
calls fread()
to read nitems
of type wchar_t
, each size
bytes in size, into an array of BUFSIZ
elements, wbuf
. However, the expression used to compute the value of nitems
fails to account for the fact that unlike the size of char
, the size of wchar_t
may be greater than 1. Thus, fread()
may attempt to form pointers past the end of wbuf
and use them to assign values to non-existing elements of the array. Such an attempt results in undefined behavior 103. A likely manifestation of this undefined behavior is classic buffer overflow which is often exploitable by code injection attacks.
Code Block | ||
---|---|---|
| ||
void f(FILE *file) {
wchar_t wbuf[BUFSIZ];
const size_t size = sizeof *wbuf;
const size_t nitems = sizeof wbuf;
size_t nread;
nread = fread(wbuf, size, nitems, file);
/* ... */
}
|
Compliant Solution
The compliant solution is to correctly compute the maximum number of items for fread()
to read from the file.
Code Block | ||
---|---|---|
| ||
void f(FILE *file) {
wchar_t wbuf[BUFSIZ];
const size_t size = sizeof *wbuf;
const size_t nitems = sizeof wbuf / size;
size_t nread;
nread = fread(wbuf, size, nitems, file);
/* ... */
}
|
Risk Assessment
...