strcmp有什么问题?

时间:2014-06-22 16:54:25

标签: c string deprecated strcmp

在对 Reading In A String and comparing it C 问题的回复中,不止一个人不鼓励使用strcmp(),说

之类的内容
  

我也强烈建议你习惯使用strncmp()   现在,...以避免许多问题。

或(在Why does my string comparison fail?中)

  

确保使用strncmp而不是strcmp。 strcmp是深刻的   不安全的。

他们指的是什么问题?

scanf() with string specifiersgets() are strongly discouraged的原因是因为它们几乎不可避免地导致缓冲区溢出漏洞。但是,使用strcmp()溢出缓冲区是不可能的,对吧?

  

“缓冲区溢出或缓冲区溢出是一种异常现象,程序在将数据写入缓冲区时会超出缓冲区的边界并覆盖相邻的内存。”

( - Wikipedia: buffer overflow)。

由于strcmp()函数永远不会写入任何缓冲区,strcmp()函数不会导致缓冲区溢出,对吗?

人们不鼓励使用strcmp(),并推荐strncmp()的原因是什么?

3 个答案:

答案 0 :(得分:14)

虽然strncmp可以阻止您超越缓冲区,但其主要目的不是安全。相反,它存在于只想比较(正确可能是NUL终止的)字符串的前N个字符的情况。

来自man page

  

strcmp()函数会比较两个字符串s1s2。如果找到s1,则返回小于,等于或大于零的整数,小于,匹配或大于s2

     

strncmp()函数类似,只是它比较ns1的唯一第一个(最多)s2字节。

请注意,在这种情况下,strncmp不能替换为简单的memcmp,因为您仍然需要利用其停止在NUL上的行为,以防其中一个字符串短于n

如果strcmp导致缓冲区溢出,则两种情况之一为真:

  1. 您的数据预计不会被NUL终止,而您应该使用memcmp代替。
  2. 您的数据 预计会被NUL终止,但是当您填充缓冲区时,您已经搞砸了,不知道NUL终止它。

  3. 请注意,超过缓冲区末尾的读取仍被视为缓冲区溢出。虽然它可能似乎无害,但它可能与一样危险。

    阅读,写作,执行......这并不重要。对非预期地址的任何内存引用都是未定义的行为。在最明显的情况下,您尝试访问未映射到进程的地址空间的页面,从而导致页面错误,以及随后的SIGSEGV。在最坏的情况下,有时会遇到\ 0字节,但有时会遇到其他缓冲区,导致程序行为不稳定。

答案 1 :(得分:6)

字符串按照定义"由第一个空字符"终止并包含的连续字符序列。

strncmp()strcmp()更安全的唯一情况是,当您将两个字符数组作为字符串进行比较时,您确定两个数组都至少为{{1} } long(第3个参数传递给n),并且你确定两个数组都包含字符串(即包含strncmp() null字符终止符)。

在大多数情况下,您的代码(,如果它是正确的)将保证任何应该包含以null结尾的字符串的数组实际上都包含以空字符结尾的字符串。

'\0'中添加n并不是一个使不安全代码安全的魔杖。它不会防止空指针,未初始化的指针,未初始化的数组,不正确的strncmp()值,或者只传递不正确的数据。无论哪种功能,你都可以用脚射击自己。

如果您尝试使用认为的数组调用nstrcmp包含以空字符结尾的字符串,但实际上并非如此,那么你的代码已经有了一个bug。使用strncmp可能会帮助您避免该错误的直接症状,但它无法修复它。

答案 2 :(得分:2)

strcmp将两个字符串字符与字符进行比较,直到检测到差异或在其中一个字符处找到\0为止。

另一方面,strncmp提供了一种限制要比较的字符数的方法,因此如果字符串不以\0结尾,则在大小限制之后函数将不会继续检查已经到达。

想象一下,如果要在这两个内存区域比较两个字符串会发生什么:

0x40, 0x41, 0x42,... 0x40, 0x41, 0x42,...

而你只对两个第一个角色感兴趣。不知怎的,\0已从字符串末尾删除,第三个字节恰好在两个区域重合。如果strncmp参数为2,num将避免比较第三个字节。

修改 如下面的评论所示,这种情况来自于语言的错误或非常具体的使用。