SAL Annotations
If you examine the library header files, you may notice some unusual annotations, for example, _In_z and _Out_z_cap_(_Size). These are examples of the Microsoft source-code annotation language (SAL), which provides a set of annotations to describe how a function uses its parameters, for example, the assumptions it makes about them and the guarantees it makes on finishing. The header file <sal.h> defines the annotations.
You can put an annotation before either the type of a function parameter or its return type, and use the annotation to describe the behavior of the function regarding the parameter or the return value. There are two classes of annotations: buffer annotations and advanced annotations. A buffer annotation describes how a function uses its pointer parameter, and an advanced annotation either describes complex or unusual buffer behavior, or provides additional information about a parameter that is not otherwise expressible.
For performance reasons, the SAL annotations do not expand unless you specify the /analyze compiler option. Therefore, the compiler will not detect invalid macros unless you specify the /analyze compiler option. You can override this behavior if you define _USE_ATTRIBUTES_FOR_SAL as 1, or specify /D_USE_ATTRIBUTES_FOR_SAL on the command line for the compiler. In both of these scenarios, the compiler expands the SAL annotations without requiring the /analyze option.
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 one buffer (which could be a string, a fixed-length or variable-length array, or just a pointer) that the function interacts with. The description includes where the buffer 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 by using the information in the tables in this section. Pick an appropriate value from the Layers table, and then add any appropriate options from the Options table. The values and options are described in the subsequent tables. Some combinations of values do not make sense as buffer annotations. Only meaningful annotations can be added to code. For a list of these, see the buffer annotation definitions section in <sal.h>.
Use only one buffer annotation for each parameter.
Layers |
Possible Values |
---|---|
Parameters layer |
(none) _In_ _Out_ _Inout_ _Deref_out_ |
Return Value layer |
_Ret_ _Deref_ret_ |
Pre / Post layer (Use this only if no suitable option exists in the Parameters layer or the 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) |
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. Use this only 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_ |
Applies to output parameters that are de-referenced. 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. Use this only for alloc and free functions. |
_Ret_ |
The function will provide the buffer and initialize it. |
_Deref_ret_ |
Applies to return values that are de-referenced. 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. Use the values in this layer only 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 de-referenced pointer parameters that must be met before the call. |
_Deref_post_ |
Describes conditions that must apply after a function is called. |
Optional Option
Describes whether 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 it is de-referenced. |
Null-Termination Option
States whether 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
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 have 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 readable 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 have 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 by using the regular buffer macros. Advanced annotations may be used either to annotate buffer parameters that involve complex or conditional behavior, or to add information to existing annotations.
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 guarantees of the function (as given by other annotations) must hold. If expr is false at exit, the caller should not expect any of the guarantees of the function to hold. If expr is not used, the function must always satisfy its guarantees. expr is added automatically to functions that indicate success in standard ways, such as by returning an HRESULT. |
Coding Tip
Some library headers control whether an annotation is in effect by using the #define directive and a corresponding preprocessor definition (/D) compiler option. For example, the crtdefs.h header defines the _Check_return_opt macro, and then selectively uses that macro instead of the _Check_return_ annotation. If the corresponding _CA_SHOULD_CHECK_RETURN preprocessor definition is defined, _Check_return_opt is defined to be _Check_return_. Otherwise, _Check_return_opt is defined to be nothing and the _Check_return_ annotation is not used.