静态分析程序(LDRA),以下语句存在问题:
const float range_min = p_results_phase->range_min;
分析器表示需要测试指针
p_results_phase
是否为NULL。
定义如下:
Cal_Ver_Results_t const * const p_results_phase = &results[test_num][CAL_VER_PHASE];
数组
results
在函数声明中定义:
void DrawVACalibrationVerificationResultsScreen(Cal_Ver_Results_t results[][CAL_VER_SI_COUNT], unsigned int test_num)
我的理解是指针
p_results_phase
不能为NULL,因为指针被分配指向数组results
内的某个位置。
Cal_Ver_Results_t const * const p_results_phase = &results[test_num][CAL_VER_PHASE];
const float range_min = p_results_phase->range_min;
const float range_max = p_results_phase->range_max;
p_results_phase
变量越界,指针test_num
是否会被赋值为NULL?p_results_phase
越界,指针CAL_VER_PHASE
是否会被赋值为NULL?Cal_Ver_Results_t
的定义:
typedef struct Cal_Ver_Results_s {
float result1;
float result2;
float range_min;
float range_max;
_Bool pass;
}Cal_Ver_Results_t;
指针值是根据作为函数参数接收的数组的地址计算的。如果数组是在本地定义的,并且假设元素位于数组边界内,则指针不能为空,但尽管函数定义中使用数组语法,
result
仍作为指针传递,因此函数可以接收空指针作为参数。在这种情况下,将 ptr
计算为 &results[test_num][CAL_VER_PHASE]
具有未定义的行为,并且指针将无效。因此,您应该首先检查 result
是否不是空指针。
答案是是的,如果你运气不好的话。
特别是,您需要确保:
参数
results
不是NULL
。尽管它在语法上声明为数组,但实际上它的行为与普通指针非常相似。
正如你所说,
test_num
是在界限之内的。超出范围可能不会导致 p_result_phase
成为 NULL
,这将是一个不幸的巧合,但它会指向任何地方并导致 UB。
CAL_VER_PHASE
也应该有一个有效值,但习惯上大写标识符是常量,所以它的值应该没问题(请检查)。
- 如果 test_num 变量越界,指针 p_results_phase 是否会被赋值为 NULL?
不。它的未定义行为。如果您使用越界索引,您可能会指向与预期不同的内存地址。例如:
a[i]
计算为 (a + i)
,其中 a
是数组的基地址,i
是数组的索引。a[-100]
,它只会指向内存地址 (a + (-100)) == (a-100)
,并且如果该地址位于程序的虚拟地址空间内,那么您最终将读取不正确的值,另一方面,写入这样的内存地址将覆盖该内存位置上存在的内容,这可能会导致其他严重问题。如果指针 p_results_phase 会被赋值为 NULL CAL_VER_PHASE 超出范围?
同样的答案。数组索引越界意味着您正在读取/写入非预期的内存位置。对这些内存地址执行读/写操作将导致未定义的结果。