翻译与节选与理解选自msdn。https://msdn.microsoft.com/en-us/library/hh916383.aspx
Simply stated, SAL is an inexpensive way to let the compiler check your code for you.
当无SAL时,c++代码如下:
void * memcpy(
void *dest,
const void *src,
size_t count
);
如果只有声明那么我们并不知道这个有什么用,没有SAL我们只能依靠注释,注释是这样解释这个函数的:
"Copies count bytes of src to dest. If the source and destination overlap, the behavior of memcpy is undefined. Use memmove to handle overlapping regions.
Security Note: Make sure that the destination buffer is the same size or larger than the source buffer. For more information, see Avoiding Buffer Overruns."
-
memcpy copies the count of bytes from the source buffer to the destination buffer.
-
The destination buffer must be at least as large as the source buffer.
但是编译器并不知道这个函数是干嘛用的,他也不知道这两个buffer 和count之间的关系。于是SAL提供了一个更清晰的解释。
void * memcpy(
_Out_writes_bytes_all_(count) void *dest,
_In_reads_bytes_(count) const void *src,
size_t count
);
这种语法规则有很多好处,the semantic patterns that SAL provides can improve the efficiency and effectiveness of automated code analysis tools in the early discovery of potential bugs. Imagine that someone writes this buggy implementation of wmemcpy:
wchar_t * wmemcpy(
_Out_writes_all_(count) wchar_t *dest,
_In_reads_(count) const wchar_t *src,
size_t count)
{
size_t i;
for (i = 0; i <= count; i++) { // BUG: off-by-one error
dest[i] = src[i];
}
return dest;
}
This implementation contains a common off-by-one error. Fortunately, the code author included the SAL buffer size annotation—a code analysis tool could catch the bug by analyzing this function alone.
SAL定义了4种基本类型的参数,这四种参数都可以用作有用的模式。
类别 | 参数注释 | 描述 |
Input to called function | _In_ | 被传送进函数的数据,只读 |
Input to called function, and output to caller | _Inout_ | 被传送进函数的数据,potential可以被修改 |
Output to caller | _Out_ | caller提供空间给被叫的函数,让该函数将数据写入这个空间。 |
Output of pointer to caller | _Outptr_ | like Output to caller,The value that's returned by the called function is a pointer. |
这四个基本注解可以通过多种方式表示的更加清晰。默认的注解指针参数被设定成必须要有值才可以----如果程序要成功运行那么他们不能为空。
这些基本注解最通用的变化是他们可以指定一个指针为空----函数能够成功运行即使为null。
下面的表显示了这些optional和required的区别:
These four basic annotations can be made more explicit in various ways. By default, annotated pointer parameters are assumed to be required—they must be non-NULL for the function to succeed. The most commonly used variation of the basic annotations indicates that a pointer parameter is optional—if it's NULL, the function can still succeed in doing its work.
This table shows how to distinguish between required and optional parameters:
Parameters are required | Parameters are optional | |
---|---|---|
Input to called function | _In_ | _In_opt_ |
Input to called function, and output to caller | _Inout_ | _Inout_opt_ |
Output to caller | _Out_ | _Out_opt_ |
Output of pointer to caller | _Outptr_ | _Outptr_opt_ |