Skip to content

Conversion operations

David Tarditi edited this page May 10, 2018 · 6 revisions

Implicit type conversions

C allow implicit conversion operations at assignments, function call arguments, and function returns. For pointer types, conversions between void * pointers and other pointer types are allowed. When an expected type differs from the actual type, and one type is void * and other type is a pointer type, an impicit conversion is done.

The Checked C extension allows implicit conversions between different kinds of pointer types as these same program locations. The conversions must meet target bounds requirements at compile time and cannot be points of runtime failure.

Conversions from unchecked pointer types

A T * can be converted to a _Ptr<T> or _Array_ptr<T>. There are only a few kinds of T * expressions that have known bounds, though:

int x;
_Ptr<int> p = &x;       // OK, &x meets bounds requirements.
_Array_ptr<int> p = &x; // OK, no bounds required.
_Array_ptr<int> p : count(1) = &x; // OK, &x meets bounds requirements.
_Array_ptr<int> p : count(2) = &x; // Error, &x does not meet bounds requirements.

int arr[10];
_Ptr<int> r = arr;       // OK, arr meets bounds requirements.
_Array_ptr<int> r = arr; // OK, no bounds required.
_Array_ptr<int> r : count(10) = r;  // OK, arr meets bounds requirements.
_Array_ptr<int> r : count(11) = r;  // Error, x does not meet bounds requirements.

f(int *x) {
  _Ptr<int> p = x;                  // Error, x does not bounds requirements for Ptr.
  _Array_ptr<int> r : count(1) = x; // Error, x does not bounds requirement.
}

Conversions between checked pointer types

Some conversions between checked pointers to the same type are allowed:

  • _Ptr<T> can be converted to _Array_ptr<T>
  • _Array_ptr<T> can be converted to _Ptr<T>
  • _Nt_array_ptr<T> can be converted to _Ptr<T> or _Array_ptr<T>.
// Implicit conversion from _Ptr<int> to _Array_ptr<int>
void f(_Array_ptr<int> a  count(len), int len);
void g(_Ptr<int> b) {
  f(b, 1);
}

_Array_ptr<int> c : count(5);
_Ptr<int> d = c + 2;

Conversions to unchecked pointer types

Implicit conversions from checked pointer types to unchecked pointer types are allowed only at bounds-safe interfaces, where the expected checked bounds or types have been declared. Otherwise they are not allowed.

Explicit type conversions

There are 3 conversion operators between pointer types in the Checked C extension.

In the descriptions below, the type D is the result type and must be a pointer type. The expression e must have pointer or integer type. The value of each conversion operation is the value of e reinterpreted bitwise as a value of type D.

  • C-style casts, given by (D) e. If D is _Ptr<T> or T *, e must have space for a value of type T. This must be provable at compile-time. Runtime failures cannot occur at these casts.
  • Dynamically-checked bounds casts, given by _Dynamic_bounds_cast<T>(e,bounds-expr). The bounds of e are checked at runtime against bounds-expr. If the bounds are not satisfied, a runtime fault is signalled. If D is a _Ptr<T> or T * type, bounds-expr is omitted and the bounds are for a single element of type T. Note that for count bounds expressions, bounds-expr are the bounds for the value at the new type T, not the original type of e.
  • Trusted bounds casts, given by _Assume_bounds_cast(e,bounds-expr). The bounds of the resulting expression are assumed to be bounds-expr. If T is a _Ptr<S> or S * type, bounds-expr is omitted.

Here are examples:

// Reinterpret a pointer to an array of characters as a pointer to an integer.
_Array_ptr<char> a : count(12) = ...
_Ptr<int> b = (_Ptr<int>) a;

// Reinterpret pointers to characters as pointers to integers.
// lb and ub have bound(unknown), so they cannot be used to access memory.
_Array_ptr<int> lb = (_Array_ptr<int>) a;
_Array_ptr<int> ub = (_Array_ptr<int>) (b + 12);

// Reinterpret a pointer to an array of characters as a pointer to an
// array of integers.  This will fail at runtime if sizeof(int) > 3.
_Array_ptr<int> c : count(3) =
    _Dynamic_bounds_cast<_Array_ptr<int>>(a, count(3));

// Create a checked_pointer to a hardware buffer.
unsigned int hardware_buf = 0xf0000;
_Array_ptr<char> d : count(4096) =
  _Assume_bounds_cast<_Array_ptr<char>>(hardware_buf, 4096);