checkedc / checkedc-llvm-project

This repo contains a version of clang that is modified to support Checked C. Checked C is an extension to C that lets programmers write C code with bounds checking and improved type-safety.
13 stars 19 forks source link

Unexpected illegal instruction at runtime for *p++ #859

Open secure-sw-dev-bot opened 2 years ago

secure-sw-dev-bot commented 2 years ago

This issue was copied from https://github.com/microsoft/checkedc-clang/issues/863


Input program:

int main(void) {
    int dst[] = { 1, 2 };
    _Array_ptr<int> p : count(2) = dst;
    *p++ = 2; // Illegal instruction
    return 0;
}

Clang version: the current master branch of checkedc-clang.

Expected: no illegal instruction error at runtime.

Got: an illegal instruction error at runtime.

There is no runtime error after breaking the statement *p++; into two lines (shown below).

int main(void) {
    int dst[] = { 1, 2 };
    _Array_ptr<int> p : count(2) = dst;
    *p = 2;
    p++;
    return 0;
}
secure-sw-dev-bot commented 2 years ago

Comment from @mgrang:

I reduced the test case further:

int main() {
  _Array_ptr<char> p : count(2) = "ab";
  *p++;
  return 0;
}

This is undefined behavior in C because we are derefencing and updating a pointer in the same statement. I talked to David about this and we decided this should be flagged as a compile-time error.

For now, in order to work-around the runtime error we should break the statement into two parts: the dereference followed by the pointer update: *p; p++;

secure-sw-dev-bot commented 2 years ago

Comment from @dopelsunce:

Note that p has self-referential bounds, i.e., bounds(p, p + 2) (expanded from count(2)). Dereference and update a pointer with self-referential bounds at the same time (in one statement) is undefined in the current Checked C spec.

Another walk-around is to remove the self-referential bounds by introducing a temporary. For example, the code below is valid:

int main() {
  _Array_ptr<char> p : count(2) = "ab";
  _Array_ptr<char> p1 : bounds(p, p + 2) = p;
  *p1++;
  return 0;
}

Note that p1 itself does not appear in its bounds.

dtarditi commented 7 months ago

This is incorrect code. Incrementing p is illegal since the upper bound of p + 2 is invalid. This code is now rejected at compile-time by the Checked C compiler.