MISRA规则18.3违规疑问:通用启动代码为何触发指针比较限制?
MISRA规则18.3判定启动代码违规的原因与修正方案
首先看触发违规的代码:
extern uint32_t __etext; extern uint32_t __data_start__, __data_end__; uint32_t* src = (uint32_t*)&__etext; // ROM location of code to be copied into ram uint32_t* dst = (uint32_t*)&__data_start__; // Start of RAM data section while (dst < &__data_end__) // Loop until we reach the end of the data section { *dst++ = *src++; }
为什么这段代码触发MISRA 18.3?
MISRA规则18.3的核心要求是:仅当指针指向同一对象(或同一数组的元素)时,才能使用<、>、<=、>=这类关系运算符。
C标准明确规定,指向不同独立对象(或不同内存区域)的指针进行关系比较属于未定义行为——不同编译器、硬件架构可能会返回不可预知的结果,甚至触发异常。MISRA作为嵌入式系统的安全编码规范,会严格禁止这类存在风险的写法。
而这段启动代码里,__data_start__和__data_end__是链接器脚本定义的独立符号,在C代码语义层面,它们是两个无关的uint32_t类型外部变量,并非同一数组的首尾元素。静态分析工具只会依据C语言语法和语义判断,不会“理解”这是链接器规划的连续内存区域,因此判定为违规。
合规的修正方案
方案1:通过计算内存长度控制循环(无需修改链接器脚本)
放弃指针比较,先算出.data段的总字节数,用循环次数控制复制流程:
extern uint32_t __etext; extern uint32_t __data_start__, __data_end__; uint8_t* src_byte = (uint8_t*)&__etext; uint8_t* dst_byte = (uint8_t*)&__data_start__; const size_t data_total_bytes = (uint8_t*)&__data_end__ - (uint8_t*)&__data_start__; for (size_t i = 0; i < data_total_bytes; ++i) { *dst_byte++ = *src_byte++; }
这里用字节指针计算长度,避免了跨对象的指针比较,完全符合MISRA规则。
方案2:将符号声明为数组类型(需配合链接器脚本)
如果可以调整链接器脚本,把__data_start__和__data_end__定义为数组的边界:
.data : { __data_start__ = .; *(.data) __data_end__ = .; } > RAM
然后在C代码里将它们声明为数组指针:
extern uint32_t __data_start__[]; extern uint32_t __data_end__[]; uint32_t* src = (uint32_t*)&__etext; uint32_t* dst = __data_start__; // 此时dst与__data_end__属于同一数组的指针,比较合法 while (dst < __data_end__) { *dst++ = *src++; }
这种方式让静态分析工具识别到两个指针指向同一数组区域,满足规则18.3的例外条件。
内容的提问来源于stack exchange,提问作者user3880296
相关产品推荐
相关产品推荐

