我写了一段代码,帮助从特定字符串中提取数据。示例:如果字符串是";ABCD*"该代码将帮助我定义"之前的最后一个字符的索引*">
char *magicchar;
int IndexofMagicchar =0;
magicchar=strchr(InputData,"*");
IndexofMagicchar = (int)(magicchar - InputData);
现在,代码工作良好,直到您使用不包含"的InputData*"那么服务将崩溃。修复方法只是在magicchar变量上添加一个简单的测试:
char *magicchar;
int IndexofMagicchar =0;
magicchar=strchr(InputData,"*");
if (magicchar!=NULL)
IndexofMagicchar = (int)(magicchar - InputData);
我的问题是,即使输入不包含"*"为什么崩溃会成为系统性的?
现在,在使用不包含">
不可信。正如其他人所评论的,strchr()
的第二个参数是int
,通过它可以直接传递要搜索的char
的值。相反,您正在传递一个指向包含该值的对象的指针,即试图间接传递该值,除非完全意外,否则这将无法按预期工作。然而,这样的程序可能不会崩溃,而是产生错误的结果。
但为了论证起见,我们假设真实的代码在这方面实际上是正确的:
char *magicchar;
int IndexofMagicchar = 0;
magicchar = strchr(InputData, '*');
IndexofMagicchar = (int) (magicchar - InputData);
该代码片段仍然存在缺陷,因为strchr
在找不到指定字符的情况下返回一个空指针,并且当任何一个操作数是空指针时,都没有定义指针差异。事实上,只有当两个操作数都指向或刚好超过同一数组的末尾时,才会定义它。程序崩溃是计算这种差异所产生的UB的最佳表现之一。然而,我倾向于猜测,实际上并不是计算崩溃的差异,而是稍后使用IndexofMagicchar
的值。
修复只是在magicchar变量上添加一个简单的测试:
char *magicchar; int IndexofMagicchar =0; magicchar=strchr(InputData,"*"); if (magicchar!=NULL) IndexofMagicchar = (int)(magicchar - InputData);
这是一个适当的解决方案,对错误的报价问题进行模运算。如果magicchar
被计算为空指针,则不应将其用作指针差操作数。它还为IndexofMagicchar
留下一个值,该值是任何字符串的有效索引,这可能是避免崩溃的关键效果。
然而,请注意,它仍然有可能使程序在以后做错误的事情,因为如果strchr
返回空指针,则IndexOfMagicchar
的结果值是,而不是'*'
外观的索引。这可能是一个健壮性问题——例如,只有当程序接收到格式错误的输入时,这一问题才会显现出来。这就是产生安全漏洞的原因,尽管特定程序的风险可能很小。
我的问题是,即使输入不包含"*"为什么崩溃会成为系统性的?
我不接受原始代码是";工作良好";。它可能没有崩溃,但那是另一回事。未定义的行为可以表现为正常工作,但任何事情都可能发生,无论是出于任何原因还是没有明显原因。
实际上,我倾向于猜测,最初的错误代码导致程序执行越界数组访问,但却恰好访问了可访问的内存,而程序中其他地方、编译选项、编译器或运行时上下文的更改导致OOB访问开始访问不可访问的存储器。然而,细节并不重要:代码是错误的,需要修复。提供的第二个版本仍然需要修复,即使它没有崩溃。
- 使用正确的类型(而不是
int
( - 写安全
strnchr
函数 strchr
的第二个参数是char
而不是char *
。字符串文字衰减为char *
指针
char *mystrnchr(const char *restrict str, size_t size, int ch)
{
char *result = NULL;
while(size && *str != ch && *str) {str++;size--;}
if(size && *str) result = (char *)str;
return result;
}
/* somewhere in another function */
char *magicchar;
ptrdiff_t IndexofMagicchar =0;
magicchar=mystrnchr(InputData, size_of_InputData, '*');
if(magicchar)
IndexofMagicchar = magicchar - InputData;
else {/* handle not found*/ }