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.

See Also

Reference

C Run-Time Libraries