【问题标题】:Does strlen() in a strncmp() expression defeat the purpose of using strncmp() over strcmp()?strncmp() 表达式中的 strlen() 是否会破坏使用 strncmp() 而不是 strcmp() 的目的?
【发布时间】:2013-01-30 20:31:48
【问题描述】:

据我了解,strcmp()(没有“n”)在任一参数中看到空字符后,会立即停止处理并返回结果。
因此,如果 100% 确定其中一个参数是空终止的(例如,它是一个字符串文字),那么在调用 @987654323 时使用 strncmp()(带有 'n')并没有任何安全优势@ 作为第三个参数的一部分,以限制与已知字符串长度的比较,因为strcmp() 将永远不会读取比已知终止字符串中更多的字符。

事实上,在我看来,在前两个参数之一上调用 strncmp() 其长度参数是 strlen() 仅与 strcmp() 的情况不同,因为它浪费的时间与大小呈线性关系通过评估 strlen() 表达式来计算已知终止字符串。

考虑:

示例代码 A:

if (strcmp(user_input, "status") == 0)
    reply_with_status();

示例代码 B:

if (strncmp(user_input, "status", strlen("status")+1) == 0)
    reply_with_status();

前者比后者有什么好处吗?因为我在其他人的代码中看到了很多很多

我对这些函数的工作原理有错误的理解吗?

【问题讨论】:

    标签: c buffer-overflow strcmp strncmp


    【解决方案1】:

    在您的特定示例中,我会说使用 strncmp 是有害的,因为:

    • 仍然使用strlen 进行扫描
    • 重复字符串文字"status"
    • 加 1 以确保字符串确实相等

    所有这些都增加了混乱,如果user_input 确实短于 6 个字符并且包含与测试字符串相同的字符,那么在任何情况下都不会防止您溢出。

    那将是例外。如果您知道输入字符串的内存总是比测试字符串中的字符数多,请不要担心。否则,您可能需要担心,或者至少考虑一下。 strncmp 对于测试大缓冲区内的东西很有用。

    我的偏好是代码可读性。

    【讨论】:

    • 我会支持你,但我没有足够的声誉。 :p 感谢您的详细回答!
    • 一些/大多数编译器可以将strlen("status") 计算为常量值。否则,同意。
    【解决方案2】:

    是的。如果在 strncmp 中使用 strlen,它将遍历指针,直到在字符串中看到 null。这使得它在功能上等同于 strcmp。

    【讨论】:

    • 我会这样说然后+1。当我使用 strncmp 时,第二个参数是 user_input 的最大大小(当 user_input 为 char [] 时通常只是 sizeof(user_input)),它是一个监护人。
    【解决方案3】:

    在您给出的特定情况下,它确实没用。然而,轻微的改变更常见:

    if (strncmp(user_input, "status", strlen("status")) == 0)
        reply_with_status();
    

    这个版本只是检查user_input是否"status"开头,所以它有不同的语义。

    【讨论】:

    • 非常好的一点,我忘了提。感谢您的回复!
    【解决方案4】:

    除了检查字符串开头是否与输入匹配的技巧之外,strncmp 只有在您不能 100% 确定字符串在其分配空间结束之前是否以空结尾时才会有用。

    所以,如果你有一个固定大小的缓冲区,你可以使用你的用户输入:

    strncmp(user_input, "status", sizeof(user_input))
    

    因此确保您的比较不会溢出。

    但是在这种情况下你必须小心,因为如果你的 user_input 不是 null 终止的,那么它会真正检查 user_input 是否匹配状态的开头。

    更好的方法可能是:

    if (user_input[sizeof(user_input) - 1] != '\0') {
      // handle it, since it is _not_ equal to your string
      // unless filling the buffer is valid
    }
    else if (strcmp(user_input, "status")) { ... }
    

    【讨论】:

    • user_input[sizeof(user_input)-1] != '\0',否则你在 user_input 数组之外。
    【解决方案5】:

    现在,我同意这不是 strncmp() 的特别有用的用法,而且我看不出它比 strcmp() 有什么好处。

    但是,如果我们通过删除strlen 之后的+1 来更改代码,那么它就开始有用了。

     strncmp(user_input, "status", strlen("status"))
    

    因为它将user_input 的前 6 个字符与 `"status" 进行比较——这至少有时是有意义的。

    所以,如果+1 存在,它就会变成常规的strcmp - 计算长度只是浪费时间。但是没有+1,这是一个非常有用的比较(在适当的情况下)。

    【讨论】:

    • 非常好。这就是那些“输入足够多的命令词来区分它”输入系统的实现方式,不是吗? if (!strncmp(command, "st", 2)) /* ... */,假设您没有其他以“st”开头的命令。感谢您的回复!
    • 是的,虽然这更像是这个伪代码count = 0; for(i : all_commands) { if (match_cmd(command, i)) { matched = i; count++; } } if (count == 1) execute_command(i); else print("need to type more...");
    【解决方案6】:

    strncmp() 的用途有限。如果在两个字符串中的任何一个上遇到 NUL,正常的 strcmp() 将停止。 (在这种情况下字符串不同) Strncmp() 将停止并返回零(“字符串在前 N 个字符中相等”)

    stncmp() 的一种可能用途是解析选项,直到不重要的部分,例如

    if (!strncmp("-st", argv[xx], 3)) {}
    

    ,对于“-string”或“-state”或“-st0”将返回零,但对于“-sadistic”返回

    【讨论】:

      猜你喜欢
      • 2017-01-02
      • 2015-07-23
      • 1970-01-01
      • 1970-01-01
      • 2011-07-14
      • 2012-10-17
      • 1970-01-01
      • 1970-01-01
      • 2012-01-08
      相关资源
      最近更新 更多