笔者来学习了解一下静态扫描以及其规则,并且亲身是实践一下对arm 架构的代码进行扫描。
1、静态扫描认识
- 静态扫描:对代码源文件按照一定的规则进行扫描,来发现一些潜在的问题或者风险,因为不涉及代码运行,所以其一般只是发现一些规范或则一些质量问题,当然这些可能存在潜在的问题和风险。
- 与静态相对应的就是动态,那么上篇文章介绍的覆盖率就是动态,通过单元测试或者模拟器,可以对源代码进行插桩,之后进行测试,可以得到动态的代码执行情况,进而转化成覆盖率。覆盖率文章可以参考这篇ARM学习(35)单元测试框架以及MinGW GCC覆盖率报告。
来举个例子,以下这段代码没有被引用,扫描就会提到:external symbol symbol was defined but not referenced
再比如,没有处理函数返回值:u8 NRF24L01_Write_Reg(u8 reg,u8 value);
会报Ignoring return value of function ‘Symbol’ (compare with Location)。
2、静态扫描规则
静态扫描规则,就是制定一些规则,扫描出哪些比较有意义的错误,其他不太重要的规则,可以先不考虑。通过我们可以参考一些已有的制定的编码规范或者规则,例如secure C或者misra 2012规则。
2.1 secure C
secure C即是:安全C 编码标准:安全、可靠和安全系统开发规则。主要是为C语言程序的开发人员设计的,其规范用来构建可靠、健壮和抗攻击的高质量系统。
来看几个规则。
2.1.1 预处理器(PRE)
建议
- PRE00. 用内联函数或静态函数代替与函数相似的宏。
- PRE01. 在宏参数名两边加上括号。
- PRE02. 宏替换列表应该加上括号。
- PRE03. 应该使用typedef定义编码类型。
- PRE04. 不要复用标准头文件名。
- PRE05. 连接标记或执行字符串化时宏替换。
- PRE06. 把文件放在包含防护条件中。
- PRE07. 避免使用连续的问号。
- PRE08. 保证头文件名唯一。
- PRE09. 不要用不安全的函数替换安全函数。
- PRE10. 在一个do-while循环中包装多条语句的宏。
规则
- PRE30. 不要通过连接创建统一字符名称。
- PRE31. 不要在不安全宏的参数中包含赋值、增值、减值、volatile访问或函数调用。
2.1.2 声明与初始化(DCL)
建议
- DCL00. 用const限定不可修改的对象。
- DCL01. 不要在子作用域中复用变量名。
- DCL02. 使用视觉区别明显的标识符。
- DCL03. 使用静态断言测试常量表达式的值。
- DCL04. 不要在一个声明中声明超过一个变量。
- DCL05. 使用typedef声明提高代码的可读性。
- DCL06. 使用有意义的符号常量表示程序逻辑中的字面值。
- DCL07. 在函数声明器中包含适当的类型信息。
- DCL08. 在常量定义中对关系进行正确的编码。
- DCL09. 把返回errno错误代码的函数的返回类型声明为errno_t。
- DCL10. 维护变参函数的编写者和调用者之间的契约。
- DCL11. 理解与变参函数相关联的类型问题。
- DCL12. 使用不透明类型实现抽象数据类型。
- DCL13. 把不会被函数修改的值指针参数声明为const。
- DCL14. 不要对跨翻译单元的全局变量的初始化顺序作出假设。
- DCL15. 把不需要外部链接的对象声明为static。
规则
- DCL30. 声明具有正确存储持久期的对象。
- DCL31. 在使用标识符之前声明他们。
- DCL32. 保证相互可见的标识符是唯一的。
- DCL33. 保证函数实参中具有限制性限定的源指针和目标指针不引用重叠的对象。
- DCL34. 对无法缓存的数据使用volatile。
- DCL35. 不要使用与函数定义不匹配的类型转换函数。
- DCL36. 不要声明具有冲突链接属性的标识符。
2.1.3 表达式(EXP)
建议
- EXP00. 使用括号保证操作的优先级。
- EXP01. 不要用指针的长度确定它所指类型的长度。
- EXP02. 注意逻辑AND和OR操作符的短路行为。
- EXP03. 不要认为结构的长度等于它的各个成员的长度之和。
- EXP04. 不要在结构之间执行逐字节的比较。
- EXP05. 不要转换掉const限定。
- EXP06. sizeof操作符的操作数不应该包含副作用。
- EXP07. 不要在表达式中对常量的值做出假设而削弱常量的优点。
- EXP08. 确保正确地使用指针运算。
- EXP09. 使用sizeof确定类型或变量的长度。
- EXP10. 不要依赖子表达式的求值顺序或副作用的发生顺序。
- EXP11. 不要把期待一种类型的操作符应用于一种不兼容的类型。
- EXP12. 不要忽略函数的返回值。
规则
- EXP30. 不要依赖序列点之间的求值顺序。
- EXP31. 避免断言的副作用。
- EXP32. 不要转换掉volatile限定。
- EXP33. 不要引用未初始化的内存。
- EXP34. 保证不对null指针进行解引用。
- EXP35. 不要在后续的序列点之后访问或修改一个函数的调用结果中的数组。
- EXP36. 不要把指针转换为对齐要求更严格的指针类型。
- EXP37. 调用函数时使用API所指定的参数。
2.1.4 整形数据(INT)
建议
- INT00. 理解编译器所使用的数据模型。
- INT01. 使用rsize_t或size_t类型表示所有对象长度的整数值。
- INT02. 理解整数转换规则。
- INT03. 使用安全的整数库。
- INT04. 对来自不信任来源的整数值实行限制。
- INT05. 如果输入函数无法处理所有可能出现的错误,就不要用它们转换字符数据。
- INT06. 使用strtol()或相关函数把字符串标记转换为整数。
- INT07. 只使用显式的有符号或无符号char类型表示数值。
- INT08. 验证所有的整数值位于范围内。
- INT09. 保证枚举常量映射到唯一的值。
- INT10. 使用%操作符时不要假设余数总是正的。
- INT11. 把指针转换为整数或者把整数转换为指针时需要小心。
- INT12. 当普通的整数位段用于表达式时,不要对它的类型做出假设。
- INT13. 只对无符号操作数使用位操作符。
- INT14. 避免在同一个数据上执行位操作和算术运算。
- INT15. 在程序员定义的整数类型的格式化IO中使用intmax_t或者uintmax_t。
规则
- INT30. 保证无符号整数运算不产生回绕。
- INT31. 保证整型转换不会丢失或错误解释数据。
- INT32. 保证有符号整数运算不会产生溢出。
- INT33. 保证除法和求模运算不会导致除零错误。
- INT34. 移位的数量不能是负数或大于操作数的位数。
- INT35. 把整型表达式比较或赋值为一种较大类型之前用这种较大类型对它进行求值。
2.1.5 浮点数(FCP)
建议
- FLP00. 理解浮点数的限制。
- FLP01. 在重新排列浮点表达式时需要注意。
- FLP02. 需要精确计算时避免使用浮点数。
- FLP03. 检测和处理浮点错误。
规则
- FLP30. 不要使用浮点数作为循环计数器。
- FLP31. 不要用复数调用期望接受实数的函数。
- FLP32. 防止或检测数学函数中的定义域错误和值域错误。
- FLP33. 执行浮点运算时把整数转换为浮点数。
- FLP34. 保证浮点数转换位于新类型的范围之内。
2.1.6 数组(ARR)
建议
- ARR00. 理解数组的工作方式。
- ARR01. 获取数组的长度时不要对指针应用sizeof操作符。
- ARR02. 显示地指定数组的边界,即使它已经由初始化值列表隐式地指定。
规则
- ARR30. 保证数组索引位于合法的范围之内。
- ARR31. 在所有源文件中使用一致的数组记法。
- ARR32. 保证变长数组的长度参数位于合法范围之内。
- ARR33. 保证复制的目标具有足够的存储空间。
- ARR34. 保证表达式中的数组类型是兼容的。
- ARR35. 不允许循环迭代到数组尾部之后。
- ARR36. 不要对两个并不指向同一个数组的指针进行相减或比较。
- ARR37. 不要把一个指向非数组对象的指针加上或减去一个整数。
- ARR38. 如果结果值并不引用合法的数组元素,不要把指针加上或减去一个整数。
2.1.7 字符和字符串(STR)
建议
- STR00. 使用适合的类型表示字符。
- STR01. 采纳和实现一致的字符串管理计划。
- STR02. 对传递给复杂子系统的字符串数据进行净化。
- STR03. 不要意外地阶段null结尾的字节字符串。
- STR04. 使用普通char类型表示基本字符集中的字符。
- STR05. 引用字符串常量时使用const指针。
- STR06. 不要以为strtok()会使解析的字符串不被修改。
- STR07. 使用托管字符串开发新的字符串操纵代码。
规则
- STR30. 不要试图修改字符串常量。
- STR31. 保证字符串的储存具有足够的空间容纳字符数据和null结尾符。
- STR32. 根据需要将字符串用null结尾。
- STR33. 正确地判断宽字符串的长度。
- STR34. 在转换为更大的整型长度时把字符转换为无符号类型。
- STR35. 不要把未检查边界来源的数据复制到固定长度的数组。
- STR36. 不要指定用字符串常量初始化的字符数组
- STR37. 字符处理函数的参数必须能够用unsigned char表示。
2.1.8 (MEM)
建议
- MEM00. 在同一个模块、同一个抽象层中分配和释放内存。
- MEM01. 在free()之后立即在指针中存储一个新值。
- MEM02. 把内存分配函数的调用结果立即转换为指向被分配类型的指针。
- MEM03. 及时清除存储在可复用资源中的敏感信息。
- MEM04. 不要执行零长度的分配。
- MEM05. 避免大型的堆栈分配。
- MEM06. 保证敏感数据不会写入到磁盘。
- MEM07. 保证calloc()的参数相乘后可以用size_t表示。
- MEM08. 只把realloc()用于改变动态分配数组的大小。
- MEM09. 不要假设内存分配函数会对内存进行初始化。
- MEM10. 定义和使用指针验证函数。
规则
- MEM30. 不要访问已释放的内存。
- MEM31. 动态分配的内存只应释放一次。
- MEM32. 检测和处理内存分配错误。
- MEM33. 使用正确的语法表示灵活数组成员。
- MEM34. 只释放动态分配的内存。
- MEM35. 为对象分配足够的内存。
2.1.9 (输入输出流)
建议
- FIO00. 在创建格式字符串时应该小心。
- FIO01. 调用通过文件名标识文件的函数时必须小心。
- FIO02. 对来自不信任来源的路径名进行标准化。
- FIO03. 不要对fopen()和文件的创建做出假设。
- FIO04. 检测和处理输入和输出错误。
- FIO05. 使用多个文件属性标识文件。
- FIO05. 创建具有正确访问权限的文件。
- FIO07. 用fseek()代替rewind()。
- FIO08. 在打开的文件上调用remove()时应该小心。
- FIO09. 跨系统传输二进制数据时应该小心。
- FIO10. 使用rename()函数时应该小心。
- FIO11. 指定fopen()的mode参数时应该小心。
- FIO12. 使用setvbuf()代替setbuf()。
- FIO13. 不要压回多余1个的字符。
- FIO14. 理解文件流的文本模式和二进制模式的区别。
- FIO15. 保证文件操作在安全目录中执行。
- FIO16. 通过创建jail限制对文件的访问。
规则
- FIO30. 排除格式字符串中的用户输入。
- FIO31. 不要打开已经被打开的文件。
- FIO32. 不要在专用于文件的设备上执行操作。
- FIO33. 检测和处理导致未定义行为的输入输出错误。
- FIO34. 使用int捕捉字符I/O函数的返回值。
- FIO35. 当sizeof(int)==sizeof(char)时,使用feof()和ferror()检测文件尾和文件错误。
- FIO36. 不要假设fgets()会读取换行符。
- FIO37. 不要假设被读取的是字符数据。
- FIO38. 不要使用FILE对象的拷贝进行输入和输出。
- FIO39. 不要在没有干预刷新或定位调用的情况下,在一个流中交替地执行输入和输出。
- FIO40. 在fgets()失败时重置字符串。
- FIO41. 调用getc()或putc()时不要使用具有副作用的流参数。
- FIO42. 保证当文件不再需要时及时将它们关闭。
- FIO43. 不要在共享目录中创建临时文件。
- FIO44. 只在fsetpos()中使用fgetpos()所返回的值。
2.1.10 环境(ENV)
建议
- ENV00. 不要存储指向getenv()返回的字符串的指针。
- ENV01. 不要对环境变量的长度做出假设。
- ENV02. 注意具有相同的有效名称的多个环境变量。
- ENV03. 调用外部程序时对环境进行净化。
- ENV04. 如果不需要命令处理器就不要调用system()。
规则 - ENV30. 不要修改getenv()返回的字符串。
- ENV31. 在可能无效化环境指针的操作之后不能再依赖它。
- ENV32. 所有的atexit处理函数都不能以除了正常返回之外的其它任何方式终止。
2.1.11 信号(SIG)
建议
- SIG00. 屏蔽由不可中断的信号处理函数处理的信号。
- SIG01. 理解与信号处理函数的持久性有关的平台特定的细节。
- SIG02. 避免使用信号实现常规的功能。
规则
- SIG30. 只在信号处理函数中调用异步安全的函数。
- SIG31. 不要访问和修改信号处理函数中的共享对象。
- SIG32. 不要在信号处理函数中调用longjmp()。
- SIG33. 不要递归地低啊用raise()函数。
- SIG34. 不要在不可中断的信号处理函数内部调用signal()。
2.1.12 错误处理(ERR)
建议
- ERRO00. 采用和实现一致的、全面的错误处理策略。
- ERRO01. 使用ferror()而不是errno检查FILE流错误。
- ERRO02. 避免带内错误提示符。
- ERRO03. 调用TR24731-1所定义的函数时使用运行时约束处理函数。
- ERRO04. 选择一种适当的终止策略。
- ERRO05. 独立于应用程序的代码应该在不提示错误处理的情况下提供错误检测。
- ERRO06. 理解assert()和abort()的终止行为。
规则
- ERRO30. 调用设置errno的库函数之前把errno设置为0,并且在函数返回一个提示失败的值之后检查errno。
- ERRO31. 不要重定义errno。
- ERRO32. 不要依赖errno的不确定值。
2.1.13 环境(ENV)
建议
- MSC00. 在高警告级别进行干净的编译。
- MSC01. 实现逻辑完整性。
- MSC02. 避免因为省略所导致的错误。
- MSC03. 避免因为多余所导致的错误。
- MSC04. 用一种可读的风格,一致地使用注释。
- MSC05. 不要直接维护time_t类型的值。
- MSC06. 处理敏感数据时注意编译器的优化。
- MSC07. 检测和删除死代码。
- MSC08. 库函数应该对形参进行验证。
- MSC09. 字符编码:使用ASCII的子集以保证安全。
- MSC10. 字符编码:UTF-8相关的问题。
- MSC11. 使用断言进行诊断测试。
- MSC12. 检测和删除没有效果的代码。
- MSC13. 检测和删除未使用的值。
- MSC14. 不要引入不必要的平台依赖性。
- MSC15. 不要依赖未定义的行为。
规则
- MSC30. 不要使用rand()函数产生伪随机数。
- MSC31. 保证返回值与适当的类型进行比较。
2.1.14 并发性(Concurrency)
2.1.15 其他(MSC)
建议
- MSC00. 在高警告级别进行干净的编译。
- MSC01. 实现逻辑完整性。
- MSC02. 避免因为省略所导致的错误。
- MSC03.避免因为多余所导致的错误。
- MSC04. 用一种可读的风格,一致地使用注释。
- MSC05. 不要直接维护time_t类型的值。
- MSC06. 处理敏感数据时注意编译器的优化。
- MSC07. 检测和删除死代码。
- MSC08. 库函数应该对形参进行验证。
- MSC09.字符编码:使用ASCII的子集以保证安全。 MSC10. 字符编码:UTF-8相关的问题。 MSC11. 使用断言进行诊断测试。
- MSC12. 检测和删除没有效果的代码。
- MSC13. 检测和删除未使用的值。
- MSC14. 不要引入不必要的平台依赖性。
- MSC15.不要依赖未定义的行为。
规则
- MSC30. 不要使用rand()函数产生伪随机数。
- MSC31. 保证返回值与适当的类型进行比较
2.2 Misra2012
详情可以参考这里MISRA-C 2012-规则介绍中文.
3、静态扫描工具
3.1 pclint工具
pclint就是一个静态扫描工具,内嵌很多规则,扫描文件时,会对源文件进行预处理,来达到扫描的效果。
- 输入头文件路径
- 输入库的路径
- 输入相关配置宏
- 输入lnt文件,pclint提供的各个平台下面的lnt文件,可以用来屏蔽规则
接着来看一下使用,
屏蔽规则:
-e# Inhibit message number # !e# Inhibit message # this line
-e(#) Inhibit for next expression --e(#) For entire current expression
-e{#} Inhibit for next {region} --e{#} For entire current {region}
-eai Args differ sub-integer -ean Args differ nominally
-eas Args same size -eau Args differ signed-unsigned
-ecall(#,<Func>) By number, fnc call -efile(#,<File>) By number, file
-efunc(#,<Func>) By number, function +efreeze disable Message inhibition
+efreeze(w<lvl>) Freeze for <lvl> ++efreeze[(w<lvl>)] Deep-freeze <lvl>
-elib(#) Within library headers -elibcall(#) Calls to library fnctns
-elibmacro(#) For all library macros -elibsym(#) For all library symbols
-emacro(#,Symbol) Within macro -emacro((#),Symbol) Within expr macro
--emacro((#),Symbol) Within expr macro -emacro({#},Symbol) Next stmt macro
--emacro({#},Symbol) Within stmt macro -epn Pointers to nominal
-epnc Pointers to nominal chars -epp Pointers are pointers
-eps Pointers to same size -epu Pointers to signed-unsigned
-epuc Pointers to sgnd-unsgnd chars -estring(#,String) By number, string
------> quit (q), previous (p), or next [n] n
-esym(#,Symbol) By number, symbol +esym(#,Symbol) Enable by no. symbol
-etd(<TypeDiff>) Ignore type diff. -etemplate(#) In template expansion
-etype(#,<TypeName>) By number, type -limit(n) Limits number of messages
++limit(n) Locks in limit of n -save Saves error inhibitions
-restore Resets error inhibitions -restore_at_end Restores at module end
-w<lvl> Set warning level (0,1,2,3,4) -wlib(<lvl>) Library warning level
-zero Sets exit code to 0 -zero(#) like -zero unless msg no. < #
常见的屏蔽规则:“-” 代表屏蔽,“+” 代表使能,“#”代表数字
- -e# Inhibit message number # 扫描过程中,禁止某条规则,适合配置我呢见
- !e# Inhibit message # this line 禁止这一行的某条规则,适合代码
- -efile(#,) By number, file 禁止某个文件的规则,适合配置文件
- -elib(#) Within library headers 禁止lib库的头文件规则
- –emacro((#),Symbol) Within expr macro 禁止宏的规则
- -esym(#,Symbol) By number, symbol 禁止符号规则
- w Set warning level (0,1,2,3,4) 设置警告级别
- -wlib() Library warning level 设置lib库警告级别
- -efunc(#,) By number, function 禁止函数的某个规则扫描
- -zero Sets exit code to 0 -zero(#) like -zero unless msg no. < # 程序结束返回错误码还是返回0,利于集成makefile扫描
输出控制
------ Verbosity Options ------Format: -/+v[aceh-iostw#]{mf<int>*}-v... Output to stdout only-v Turn off verbosity (note absence of option letters)+v... Output to stderr and also to stdout+v Don't change options but output to stderr and stdout
Zero or more of: a Attempts to openc Unique Calls e Function templatesh Dump strong type hierarchy h- Compressed form of hi Indirect files o Display optionss Storage consumed t Template expansionsw Specific Walks # Append file ID nos.
One of:m Module names (the default) f Header Files (implies m)<int> Every <int> lines (implies f) * All verbosity
------> quit (q), previous (p), or next [n]
输出格式控制
-h[abefFrsSm/<M>/<I>]<ht> message height (default = -ha_3)a Position indicator Above line b Indicator Below linef Frequent file information F Always produce file infoe Place source line @ End of msg r Repeat source line each msgs Space after each non-wrapup msg S space after each msgm/<M>/ Macro indicator is <M> mn Turn off macro indication<I> The position Indicator <ht> Height of messages
-width(<Width>,<Indent>) Message width (default = -width(79,4))
-append(errno,msg) Appends msg for message errno
-format=... Specifies message format
-format4a=, -format4b= Specifies format if msg. ht. = 4
-format_specific=... Prologue to specific Walk messages
-format_stack=... Format for output of stack information
-format_template=... Format for prologue to template instantiation
-format_verbosity=... Format for verbosity under +htmlformat codes (%...) format escapes (\...)%c column no. %l Line no. \t Tab%C Column no. + 1 %m Msg text \s Space%f Filename %n msg Number \a Alarm%i FunctIon name %t msg Type \q Quote%(...%) Use ... if '%f' or '%i' are non null \\ Backslash\n Newline
+source(suboptions) Echos entire source files(s); suboptions:-number Do not number lines -indent Do not indent hdr lines-m(files) Ignore given modules +h(hdrs) Echo given hdrs-h(hdrs) Do not echo hdrs +dir(dirs) Echo hdrs from these-dir(dirs) Do not echo hdrs from +class(all) Echo all hdrs+class(project) Echo project hdrs
+html(options) Output in html format (example in env-html.lnt)version(...) Can be used to specify the version of htmlhead(file) Includes file just after <html>
+xml([name]) Activate escapes for xml (example in env-xml.lnt)If name is provided, output appears within <name> ... </name>
-message(String) Output String as an informational message
-summary([out-file]) Issues or appends a summary of error messages
-t# Sets tab size to #
+typename(#) Includes types of Symbols in message #
+xml(name) Format output messages in xml.... message presentation flags ....
ffn use Full file Names (OFF) ffo Flush Output each msg (ON)
flm Lock Message format (OFF) frl Reference Location info (ON)
fsn treat Strings as Names (OFF)
3.2 pclint 工具使用
通过makefile可以批量扫描C文件。
LINT_EXEC := lint-nt.exe
LINT_FLAGS = --i"D:\Software\MinGW\include" --i"D:\Software\MinGW\lib\gcc\mingw32\6.3.0\include" -width="0,4" -format=">>> %f(%l) : %t %n : %m"
LINT_FLAGS += gcc.lnt
LINT_FLAGS += $(C_INCLUDE)
LINT_FLAGS += -dSTM32F405xx
LINT_FLAGS += -dSTM32F40_41xxx
LINT_FLAGS += -dUSE_STDPERIPH_DRIVER
LINT_FLAGS += -d__UVISION_VERSION="537"
LINT_FLAGS += -ID:/Software/Keil/pack/Keil/STM32F4xx_DFP/2.13.0/Drivers/CMSIS/Device/ST/STM32F4xx/Include# compiler objectsLINT_OBJECTS = $(addprefix $(BUILD_lnt_DIR)/,$(notdir $(C_SOURCE:.c=.lnt)))vpath %.c $(sort $(dir $(C_SOURCE)))$(shell mkdir -p $(BUILD_lnt_DIR))ifeq ($(silent), )
MAKEFLAGS += --silent
endif.PHONY : lint
lint :$(BUILD_lnt_DIR)/$(TARGET).lnt$(BUILD_lnt_DIR)/$(TARGET).lnt: $(LINT_OBJECTS)$(ECHO) generate $(TARGET).lnt > $(BUILD_lnt_DIR)/$(TARGET).lnt# lint process
$(BUILD_lnt_DIR)/%.lnt : %.c $(ECHO) 'PClint Anazlay' $<$(LINT_EXEC) $(LINT_FLAGS) $< > $@ -zero
扫描的日志如下图所述:
PClint Anazlay ../Core/stm32f4xx_it.c
PClint Anazlay ../Core/system_stm32f4xx.c
PClint Anazlay ../Driver/src/misc.c--- Module: ..\Core\stm32f4xx_it.c (C)
PClint Anazlay ../Driver/src/stm32f4xx_adc.c_while (1)
>>> ..\Core\stm32f4xx_it.c(66) : Info 716 : while(1) ... _while (1)
>>> ..\Core\stm32f4xx_it.c(79) : Info 716 : while(1) ... _while (1)
>>> ..\Core\stm32f4xx_it.c(92) : Info 716 : while(1) ... _while (1)
>>> ..\Core\stm32f4xx_it.c(105) : Info 716 : while(1) ... _while(TimeDelay!=0);
>>> ..\Core\stm32f4xx_it.c(155) : Info 722 : Suspicious use of ;_while(TimeDelay!=0);
>>> ..\Core\stm32f4xx_it.c(161) : Info 722 : Suspicious use of ;--- Module: ..\Core\system_stm32f4xx.c (C)
PClint Anazlay ../Driver/src/stm32f4xx_dac.c--- Module: ..\Driver\src\misc.c (C)_#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
>>> ..\Core\system_stm32f4xx.c(420) : Warning 553 : Undefined preprocessor variable '__FPU_USED', assumed 0_tmp = RCC->CFGR & RCC_CFGR_SWS;
>>> ..\Core\system_stm32f4xx.c(499) : Info 838 : Previously assigned value to variable 'tmp' has not been used_if ((RCC->CR & RCC_CR_HSERDY) != RESET)
>>> ..\Core\system_stm32f4xx.c(582) : Warning 641 : Converting enum 'FlagStatus' to int_RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
>>> ..\Core\system_stm32f4xx.c(598) : Info 835 : A zero has been given as right argument to operator '|'_RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
>>> ..\Core\system_stm32f4xx.c(617) : Info 778 : Constant expression evaluates to 0 in operation '-'_(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
>>> ..\Core\system_stm32f4xx.c(618) : Info 845 : The left argument to operator '<<' is certain to be 0 [Reference: file ..\Core\system_stm32f4xx.c: line 617]
>>> ..\Core\system_stm32f4xx.c(617) : Info 831 : Reference cited in prior message_(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
>>> ..\Core\system_stm32f4xx.c(618) : Info 845 : The right argument to operator '|' is certain to be 0 [Reference: file ..\Core\system_stm32f4xx.c: line 617]
>>> ..\Core\system_stm32f4xx.c(617) : Info 831 : Reference cited in prior message_while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
>>> ..\Core\system_stm32f4xx.c(657) : Info 722 : Suspicious use of ;
3.3 pclint规则
pclint规则,后续进行补充,详情可以这里pclint静态扫描规则.
4、参考
1、C安全编码实践
2、C安全编码标准