Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Checked scopes

David Tarditi edited this page Oct 4, 2018 · 12 revisions

Overview

With the Checked C extension, bounds checking and null pointer checking is tied to the type of a pointer or an array. _Array_ptr types have bounds checking and null checking, _Ptr types have null checking, and checked array types have bounds checking.

To guarantee that all memory accesses in a region of code are checked, a _Checked scope can be used. This restricts the pointer and array types that can be used in that region to checked pointer and array types and unchecked pointer and array types with bounds-safe interfaces.

A checked scope can be declared in the following ways:

  • Using a checked compound statement: _Checked { ... }
  • Using a pragma: #pragma CHECKED_SCOPE ON. This can be used at the top-level of a file to make the rest of the file be in a checked scope. It can also be used within a compound statement, in which case it is in effect for the remainder of the scope.
  • As a declaration specifier on a function: extern _Checked int f(void) { ... }. In this case, the declaration of the function's parameters, return type, and body are within a checked scope.

Examples

A function can be declared in a checked scope in the following ways. The checked scope enforces that the parameters and return types must be checked types or have bounds-safe interfaces:

#pragma CHECKED_SCOPE ON
void f(_Array_ptr<int> p : count(len), int len);

or

_Checked void f(_Array_ptr<int>> p : count(len), int len);

A bounds-safe interface is OK:

_Checked void g(int *p : count(len), int len);

An unchecked pointer without a bounds-safe itnerface is not OK:

_Checked void g(int *p, int len);  // error.

A function can be defined in a checked scope in similar ways:

#pragma CHECKED_SCOPE ON
void f(_Array_ptr<int> p : count(len), int len) { ... }

or

_Checked void f(_Array_ptr<int>> p: count(len), int len) { ... }

Additional checking

In checked scopes, the following is not allowed also:

  • Declarations or uses of function without prototypes. A function prototype declares the expected types for arguments. In C, the function int f() is a function that has no prototype declared. For functions where no prototype is declared, arguments are passed at call sites based on their types. There could be a mismatch between the actual definition of a function and the arguments that are passed.
  • Declarations or uses of functions with variable numbers of arguments. Again, there is no way to guarantee that arguments are used at their correct type.
  • Not returning a value when is expected for a function.
  • Returning a value when none is expected for a function.
  • The _Assume_bounds_cast operator.

Unchecked scopes

By default, the top-level scope of a file is an unchecked scope. In an unchecked scope, none of the restrictions of checked scopes apply. Any functions declared in an unchecked scope are by default unchecked as well

If code in a checked scope, needs to do an operation only allowed in a unchecked scope, an unchecked scope can be declared in the following ways:

  • As an unchecked compound statement: _Unchecked { ... }
  • Using a program: #pragma CHECKED_SCOPE OFF
  • As a declaration specifier on a function extern _Unchecked int f(void) { ...}

Examples

A function can be defined in a checked scope, yet the body of the function can remain unchecked for later conversion:

#pragma CHECKED_SCOPE ON
void f(_Array_ptr<int> p : count(len), int len) _Unchecked { ... }

Syntax and static checking subtleties

The keywords _Checked and _Unchecked are treated as declaration specifiers unless they are followed by the [' or {` tokens. They are only allowed as declaration specifiers on functions.

Clone this wiki locally