SAL Annotations
If you examine the library header files, you will notice some unusual annotations such as _In_z and _Out_z_cap_(_Size). These are examples of Microsoft's standard source code annotation language (SAL), which provides a set of annotations to describe how a function uses its parameters—the assumptions it makes about them, and the guarantees it makes upon finishing. The header file <sal.h> defines the annotations.
Annotations may be placed before either a function parameter's type or its return type, and describe the function's behavior regarding the parameter or return value. There are two classes of annotations: buffer annotations and advanced annotations. Buffer annotations describe how functions use their pointer parameters, and advanced annotations either describe complex/unusual buffer behavior, or provide additional information about a parameter that is not otherwise expressible.
Buffer Annotations
The most important annotations provide a consistent way to annotate buffer parameters or return values for a function. Each of these annotations describes a single buffer (which could be a string, a fixed-length or variable-length array, or just a pointer) that the function interacts with—where it is, how large it is, how much is initialized, and what the function does with it.
The appropriate macro for a given buffer can be constructed using the tables below. Pick an appropriate value from the Layers table, and then add any appropriate options from the Options table. Some combinations of values do not make sense as buffer annotations. Only meaningful annotations can be added to your code; for a list of these, see the buffer annotation definitions section in <sal.h>.
Only a single buffer annotation should be used for each parameter.
Layers |
Possible choices |
---|---|
Parameters Layer |
(none) _In_ _Out_ _Inout_ _Deref_out_ |
Return Value Layer |
_Ret_ _Deref_ret_ |
Pre / Post Layer (used only if no suitable option exists in the Parameters layer or Return Value layer) |
_Pre_ _Post_ _Deref_pre_ _Deref_post_ |
Options |
Possible choices |
---|---|
Optional |
(none) opt_ |
Null-termination |
(none) z_ |
Extent |
(none) cap_[c_|x_](size) bytecap_[c_|x_](size) count_[c_|x_](size) bytecount_[c_|x_](size) ptrdiff_cap_(ptr) ptrdiff_count_(ptr) |
The various categories and their respective choices are described below.
Parameters Layer
Describes how the function uses the buffer of a formal parameter.
(none) |
The buffer is not accessed. The caller must provide the buffer. This should only be used for alloc and free functions. |
_In_ |
The function will only read from the buffer. The caller must provide the buffer and initialize it. |
_Out_ |
The function will only write to the buffer. The caller must provide the buffer, and the function will initialize it. |
_Inout_ |
The function may freely read from and write to the buffer. The caller must provide the buffer and initialize it. |
_Deref_out_ |
This option applies to output parameters that are dereferenced. Given a parameter p, *p is the buffer pointer. p must not be NULL. The function will only write to the buffer. The function will provide the buffer and initialize it. |
Return Value Layer
Describes how the function uses the buffer of a return value.
(none) |
The buffer is not accessed. The function will provide the buffer, and it will be uninitialized at exit. This should only be used for alloc and free functions. |
_Ret_ |
The function will provide the buffer and initialize it. |
_Deref_ret_ |
This option applies to return values that are dereferenced. Given a return value p, *p is the buffer pointer. p must not be NULL. The function will provide the buffer and initialize it. |
Pre / Post Layer
Describes how the function uses the buffer. Only use the values in this layer if the values in the Parameters layer or Return Value layer do not apply.
_Pre_ |
Describes conditions that must be met before a function is called. |
_Post_ |
Describes conditions that must apply after a function is called. |
_Deref_pre_ |
Describes conditions for array elements of dereferenced pointer parameters that must be met before the call |
_Deref_post_ |
Describes conditions that must apply after a function is called. |
Optional Option
Describes if the buffer itself is optional. These annotations can be applied to values in the Parameters layer, Return Value layer, or Pre / Post layer.
(none) |
The pointer to the buffer must not be NULL. |
opt_ |
The pointer to the buffer might be NULL. It will be checked before being dereferenced. |
Null-Termination Option
States if the presence of a '\0' marks the end of valid elements in the buffer. These annotations can be applied to values in the Parameters layer, Return Value layer, or Pre / Post layer.
(none) |
The buffer may not be null-terminated and a '\0' does not indicate the end of the buffer. |
z_ |
A '\0' indicates the end of the buffer. |
Extent Option
These options apply to readable and writable buffers. These annotations can be applied to values in the Parameters layer, Return Value layer, or Pre / Post layer.
(none) |
The parameter or return value is not a readable or writable buffer. |
cap_[c_|x_](size) bytecap_[c_|x_](size) ptrdiff_cap_(ptr) |
Describes the writable size of the buffer. This option is typically used with the _Out_ annotation. If the size is given in elements, use cap_. If the size is given in bytes, use bytecap_. If the size is given by a limiting pointer, use ptrdiff_cap_. If the buffer size is a non-constant parameter, you do not need to specify c_ or x_. For example, valid annotations include cap_(size) and bytecap_(size). If the buffer size is a constant expression, specify the c_ option. For example, valid annotations include cap_c_(size) and bytecap_c_(size). If the buffer size is neither a constant expression nor a parameter, specify the x_ option. For example, valid annotations include cap_x_(size) and bytecap_x_(size). |
count_[c_|x_](size) bytecount_[c_|x_](size) ptrdiff_count_(ptr) |
Describes the writable size of the buffer. This option is typically used with the _In_ annotation. If the size is given in elements, use count_. If the size is given in bytes, use bytecount_. If the size is given by a limiting pointer, use ptrdiff_count_. If the buffer size is a non-constant parameter, you do not need to specify c_ or x_. For example, valid annotations include count_(size) and bytecount_(size). If the buffer size is a constant expression, specify the c_ option. For example, valid annotations include count_c_(size) and bytecount_c_(size). If the buffer size is neither a constant expression nor a parameter, specify the x_ option. For example, valid annotations include count_x_(size) and bytecount_x_(size). |
Advanced Annotations
Advanced annotations describe behavior that is not expressible with the regular buffer macros. These may be used either to annotate buffer parameters that involve complex or conditional behavior, or to enrich existing annotations with additional information.
Annotation |
Description |
---|---|
_Check_return_ |
Return value must not be ignored by callers of this function. |
_Printf_format_string_ |
A string that contains % markers in the style of printf. |
_Scanf_format_string_ |
A string that contains % markers in the style of scanf. |
_Scanf_s_format_string_ |
A string that contains % markers in the style of scanf_s. |
_Success_(expr) |
expr indicates whether the function succeeded or not. If expr is true at exit, all the function's guarantees (as given by other annotations) must hold. If expr is false at exit, the caller should not expect any of the function's guarantees to hold. If not used, the function must always satisfy its guarantees. Added automatically to functions that indicate success in standard ways, such as by returning an HRESULT. |