MISRA C:2012 Rule 18.1
A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand
描述
规则定义
A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand 1 .
理由
使用无效的数组下标可能会导致程序出现错误行为。运行时派生的数组下标特别麻烦,因为它们无法通过人工审查或静态分析轻松检查。
根据 C 标准,对数组末尾之后的指针进行解引用会导致未定义的行为,不合规。
如果将一个 T*
指针转换为 char*
或 unsigned char*
指针,则转换后指针的边界被视为 sizeof(T)
。例如,在此代码中,array
可容纳类型为 unsigned char
的 4
对象。
unsigned int obj = 42; unsigned char *array = (unsigned char*) &obj; unsigned char small_obj = array[3];
Polyspace 实现
Polyspace® 在以下情况下报告违反此规则:
在数组访问期间,数组索引超出范围
[0...array_size-1]
。指针在超出其作用域范围外被解引用。
在检查是否违反本规则时,Polyspace 会考虑以下因素:
不属于数组的单个对象被视为一个元素的数组。例如,在此代码示例中,
arr_one
等同于一个元素的数组。Polyspace 不会标记指针ptr_to_one
的递增,因为它指向arr_one
的最后一个元素之后的位置。void f_incr(int* x){ int* ptr_to_one = x; ++ptr_to_one; // Compliant } void func(){ int arr_one=1; // Equivalent to array of one element f_incr(&arr_one); }
Polyspace 在指针指向数组时,不会标记指针运算中指针参数的使用。例如,在此代码片段中,当将数组传递给
f1
时,在f1
中使用&a1[2]
是合规的。void f1( int* const a1){ int* b= &a1[2]; // Compliant } void f2(){ int arr[3] {}; f1(arr); }
在具有多个元素的结构中,如果指针指向结构的已分配内存或结构的最后一个元素之后,则 Polyspace 不对指向不同元素的指针算术运算的结果进行标记。
例如,在此代码片段中,对
ptr_to_struct
的赋值是合规的,因为它仍然位于myStruct
内,即使它指向myStruct.elem1
之外。使用大于元素维度的索引来访问该元素的内容是不合规的,即使结果地址在结构的分配内存范围内也是如此。void func(){ struct { char elem1[10]; char elem2[10]; } myStruct; char* ptr_to_struct = &myStruct.elem1[11]; //Compliant // Address of myStruct.elem1[11] is inside myStruct char val_to_struct = myStruct.elem1[11]; // Non-compliant }
在多维数组中,Polyspace 标记任何使用大于子数组维度的索引来访问该子数组元素的情况。如果地址位于顶级数组的分配内存中,则 Polyspace 不标记对同一子数组元素的地址的赋值。
例如,在此代码片段中,对指针
ptr_to_arr
的赋值是合规的,因为该指针指向的是multi_arr
分配的内存范围内的地址。为变量arr_val
的赋值不合规,因为用于访问子数组元素 (3) 的索引大于子数组的维度 (2)。void func(){ int multi_arr[5][2]; // Assigned memory is inside top level array int* ptr_to_arr = &multi_arr[2][3]; //Compliant // Use of index 3 with subarray of size 2 int arr_val = multi_arr[2][3]; // Non-compliant }
Polyspace 在指针指向数组最后一个元素之后,对该指针的解引用进行标记。例如,在此代码片段中,
ptr
的赋值是合规的,但ptr
的解引用则不合规。tab+3
超过选项卡中的最后一个元素。void derefPtr(){ int tab[3] {}; int* ptr = tab+3; //Compliant int res = *(tab+3); // Non-compliant }
当指针运算的结果为
nullptr
时,Polyspace 不触发此检查项。以下列代码为例:void g(int *p); void add(int* p, int n) { g(p + n); //Compliant} void foo() { add(nullptr, 0); }
add()
中的指针运算结果为nullptr
。Polyspace 不会标记此运算。如果 Polyspace 报告指针或数组访问违反了此规则,则不再报告对指针或数组的后续访问。例如,Polyspace 在第一次递增到
pointer2array
时报告违反了此规则。修复此违规行为也可一并解决后续的越界访问问题。如果您修复了报告的问题后,仍然存在越界访问,Polyspace 会将这些访问报告为违规。#include <stdint.h> int32_t data = 0; int32_t simple_array[ 10 ] = { 0 }; void Func(void) { int32_t *pointer2array = &simple_array[ 10 ]; pointer2array++; /* Noncompliant - accessing array out of bound */ data = *pointer2array; /* Noncompliant - pointer out of bounds after increment*/ pointer2array++; /* Violation no longer reported for out of bound access*/ }
扩展检查项
当输入值未知且只有部分输入会导致问题时,默认的 Bug Finder 分析可能不会触发此规则的违规。要检查由特定系统输入值引起的违规,请运行更严格的 Bug Finder 分析。请参阅Extend Bug Finder Checkers to Find Defects from Specific System Input Values。
故障排除
如果您预期会出现违规,但未看到该违规,请参阅诊断为何编码规范违规未按预期显示。
示例
检查信息
组:指针和数组 |
类别:必需 |
AGC 类别:必需 |
版本历史记录
1 All MISRA coding rules and directives are © Copyright The MISRA Consortium Limited 2021.
The MISRA coding standards referenced in the Polyspace Bug Finder™ documentation are from the following MISRA standards:
MISRA C:2004
MISRA C:2012
MISRA C:2023
MISRA C++:2008
MISRA C++:2023
MISRA and MISRA C are registered trademarks of The MISRA Consortium Limited 2021.