分析一些代码:
static volatile UCHAR *pucSndBufferCur;
eMBErrorCode eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
{
if( eRcvState == STATE_RX_IDLE )
{
/* First byte before the Modbus-PDU is the slave address. */
pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
pucSndBufferCur[0] = ucSlaveAddress;
看起来不安全,如果地址中的内存(pucFrame - 1)已用于其他变量并覆盖它可能会导致故障。
您如何看待,这样的代码是可以使用还是错误的方式,永远不应该使用?
答案 0 :(得分:7)
从此评论中
/* First byte before the Modbus-PDU is the slave address. */
pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
我们可能会推断该函数希望调用者保证这一点。在这种情况下,如果调用者满足要求,则然后代码是安全的。
如果来电者不保证这一点,则该功能不安全。这就像您无法有效检查的任何其他先决条件一样:如果违反了要求,它们会有UB,而这是来电者的错误。
为了进行比较,free()
如果违反了从malloc()/realloc()
返回其指针参数的先决条件,则可能会有类似的行为(可能会出现更糟糕的副作用)。
看起来不安全,如果地址中的内存(pucFrame - 1)已用于其他变量并覆盖它可能会导致故障
它 不安全 - 它是C.正确使用它的责任是你的。如果你错误地使用它(传递一个不符合规定要求的指针),就会出现故障并且它们将是你的错。
您如何看待,这样的代码是可以使用还是错误的方式,永远不应该使用?
它可以安全使用,就像free()
可以安全使用一样。它可以以错误的方式使用,因为free()
可能被滥用。 从不使用这样的代码的唯一原因是你不相信自己正确使用它。
实际的建议是查看这个pucFrame
指针的来源,验证它始终保证满足要求,然后确保在指针的代码行程中不会破坏任何内容。
答案 1 :(得分:1)
语句pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
的行为将是 undefined ,除非pucFrame
是指向数组中元素的指针,或者只是在数组结束之后,并且是它之前的一个元素。为此,可以将标量视为长度为1的数组。
这是因为指针算法仅在数组中有效。
你也丢弃了const
,它可以再次将程序置于未定义的状态,这取决于你对指针的处理方式(以及C和C ++之间的规则不同)。
答案 2 :(得分:1)
永远不要假设某个地址位于特定地址之前或之后,除非您正在检查数组范围内的某些内容。
MISRA-C:2004,规则17.4(必填)或MISRA-C:2012,规则18.4(必填)数组索引应是唯一允许的指针算术形式。
强烈建议您使用像PC-Lint这样的静态分析器来检查代码的健全性,以避免未定义的行为。
此外,您可以将所有必需的东西放入结构中,只需将结构指针传递给函数即可。但即使这样,也不要使用++或 - 来访问struct成员,因为你不知道添加的填充是依赖于编译器的
答案 3 :(得分:0)
请清除问题的感觉。 无论如何代码有点不安全,但不是你告诉的原因。 为了使其更强大,您应该测试null。 指针算法有点危险,但我认为这个OLD代码会根据上下文做出一些假设。
它似乎来自:
FreeModbus Libary:Modbus ASCII / RTU的便携式Modbus实现。 3 *版权所有(c)2006 Christian Walter
所以是的,2006年的代码可能很危险,但另一方面它已经使用了15年......所以可以使用它。 (旧代码通常有效但如果你不修改它。)