如标题中所述:
SAL(源注释语言)的目的是什么?SAL 1和SAL 2之间有什么区别?
我理解使用的基础知识,这有助于突出传递给函数的每个变量的目的以及静态代码分析的各种其他内容,但它实际上有多大差异(忽略了增加的清晰度)项目中其他程序员的参数要求)?
如果我有以下原型:
_Success_(return == 1)
int TestFunction( _In_ int* pTest, _Inopt_ char* pOptional );
这应该“告诉”静态分析器该函数在成功运行时将返回1,pTest
是一个指针,它不能是nullptr
而pOptional
是指针可能是nullptr
也可能不是__out
。但是,静态分析器不能从函数定义本身获取此信息吗?此外,它如何处理获得的信息,如成功标准?
此外,为什么SAL 1和SAL 2之间存在差异,为什么microsoft决定改变他们命名宏的方式(即从_Out_
到__success
和_Success_
到{{1}}?)
如果在MSDN上有详细描述,我很抱歉,但是我无法在StackOverflow上找到它或任何其他问题并提供详细的答案,所以我想我会问我希望能满足我的好奇心。
提前感谢您的时间!
答案 0 :(得分:10)
我在你的问题中读到了多个问题,希望我得到了所有问题:
为什么要使用SAL而不只是从源代码中推断出来?
关于使用SAL明确告知分析仪有关参数行为等的详细信息,有多个答案。
虽然分析器可以从实现中推断出参数行为,但它通常无法区分意图和实施事故。作为开发人员,如果您明确说明了不同参数的预期用途,分析器可以验证您编写的实现是否满足您的意图,以及调用者是否正确使用它。
当源代码不可用于分析时,这为静态分析器提供有关函数行为的信息,例如,作为Visual Studio,驱动程序工具包等一部分提供的各种头文件中声明的函数。
SAL允许表达难以从源代码中推断的概念,例如锁定用法和驱动程序中的IRQL要求。
这也有助于与回调函数保持一致。 Windows标头描述的一些框架可能会声明一组回调函数,因此Windows框架将调用其他地方定义的回调函数(应用程序,驱动程序等)。因此Windows永远不会看到被调用函数的源,并且回调函数定义永远不会看到调用者。
分析师从成功获得哪些信息?
这与您撰写的案例无关。但是,如果存在输出参数(例如 Out 和family),则意味着如果函数不成功,则调用者不能依赖输出注释。例如:
_Success_(return) bool GetASmallInt(_Out_range_(0, 10) int& an_int);
如果GetASmallInt返回true,则an_int将介于0和10之间(包括0和10)。如果它返回false,则不存在这样的保证,并且该变量甚至可能都没有被函数初始化。
SAL 1和SAL 2有什么区别?为什么注释会从__in
重命名为_In_
?
SAL的原始定义中的一些极端情况(例如__in)没有很好地与C ++进行交互。新语法从一些较新的实现开始,确保它符合C和C ++语法的要求。
SAL 1和SAL 2之间的主要区别在于SAL 2能够表达SAL 1无法表达的许多概念,而SAL 2的定义更好,特别是对于C ++,如上所述。