Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added example of undefined behavior 59.

...

UB

Description

43

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.

44

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 * operator that is evaluated.

<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 a[1][7] given the declaration int a[4][5]).

]]></ac:plain-text-body></ac:structured-macro>

59

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
bgColor#ccccff
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
bgColor#ffcccc

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
bgColor#ccccff

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.

...