【问题标题】:How fast is strn*() compared to str*()? [duplicate]strn*() 与 str*() 相比有多快? [复制]
【发布时间】:2012-09-28 09:02:52
【问题描述】:

可能重复:
Why should you use strncpy instead of strcpy?

我正在读一本关于计算机/密码学等的书。作者经常使用 strncpy(dest, src, strlen(src)); 而不是 strcpy(dest, src); 这对我来说没有多大意义。好吧,我是一名专业程序员。

问题是:它真的有真正的不同吗?真正的应用程序使用这样的东西?

【问题讨论】:

  • 我不明白为什么strncpy(dest, src, strlen(src)); 会比strcpy(dest, src); 快。
  • @Mysticial 它的速度是一样的(尽管 strlen 增加了使用它的开销)。速度不是使用它的原因。防止缓冲区溢出是首选的原因。 (strncpystrcpy 的速度相同。假设复制相同数量的字符,内部速度相同。)顺便说一句,第三个参数不应该是字符串长度,而是而不是 dest 缓冲区的大小(或者可能是减 1 的大小)。
  • @Mystical 刚刚意识到您不是提问者,因此我之前的一半评论只是漫无边际。会留下之前的评论,但万一提问者确实觉得它有用,并且它接近长度限制,所以不能在那里写这个注释:)。

标签: c performance optimization


【解决方案1】:

几乎可以肯定,作者滥用了strn* 函数。不幸的是,几乎没有充分的理由使用strn* 函数,因为它们实际上并没有做你想做的事情。

我们来看看strcpystrncpy

char *strcpy(char *dest, const char *src);

char *strncpy(char *dest, const char *src, size_t n);

strcpy 函数将src 复制到dest,包括一个尾随\0。它很少有用:

  1. 除非您知道源字符串适合目标缓冲区,否则缓冲区溢出。缓冲区溢出是安全隐患,它们可能会使您的程序崩溃,并导致其行为不正确。

  2. 如果您确实知道源字符串和目标缓冲区的大小,您不妨使用memcpy

相比之下,strncpy 最多将srcn 字节复制到dest,然后用\0 填充其余部分。它很少有用:

  1. 除非您知道源字符串小于目标缓冲区,否则您无法确定生成的缓冲区是否会被 nul 终止。如果您假设结果是 nul 终止的,这可能会导致程序中的其他地方出错。

  2. 如果您确实知道源字符串更小,那么您不妨使用memcpy

  3. 您可以在调用strncpy 后简单地终止字符串,但您确定要静默截断结果吗?我想大多数时候,您宁愿收到一条错误消息。

为什么会有这些功能?

strcpy 函数偶尔会很方便,但它主要是人们不太关心验证输入的时代的遗迹。为程序提供太大的字符串会使程序崩溃,建议是“不要那样做”。

strncpy 函数在您想在固定大小的字段中传输数据并且不想在字段的其余部分中放入垃圾时很有用。这主要是人们使用固定大小字段的时代的遗迹。

所以你很少会在现代 C 软件中看到 strcatstrncpy

更严重的问题

但是,您的示例结合了两全其美。让我们来看看这段源代码:

strncpy(dest, src, strlen(src));

这会将src 复制到dest没有\0 终止符和没有边界检查。它结合了strcpy(无边界检查)的最差方面和strncpy(无终止符)的最差方面。看到这样的代码,赶紧跑。

如何使用字符串

良好的 C 代码通常使用以下几个选项之一来处理字符串:

  1. 使用固定缓冲区和snprintf,只要您不介意固定缓冲区即可。

  2. 使用有界字符串函数,例如 strlcpystrlcat。这些是 BSD 扩展。

  3. 使用跟踪字符串长度的自定义字符串点,并使用memcpymalloc 编写您自己的函数。

【讨论】:

  • “更糟糕的问题” - 具体来说,strncpy(dest, src, strlen(src)); 完全等同于 memcpy(dest, src, strlen(src))。所以我能想到写它的唯一原因是你不知道你在做什么,因为你写的代码看起来像一个字符串操作,而实际上它不是一个。
【解决方案2】:

如果该代码是书中的逐字副本,则作者要么不懂 C,要么不是安全专家,要么两者兼而有之。

也可能是他使用了错误配置的编译器,明确禁止使用某些已知可能不安全的函数。当编译器无法区分安全、不安全和潜在不安全时,这是一种值得怀疑的做法。

【讨论】:

    【解决方案3】:

    对 strcpy 使用 strncpy 与它的执行速度几乎没有关系,但 strncpy 大大降低了缓冲区溢出攻击的可能性。 在 C 中,指针是最强大的,但它们也使系统易受攻击。

    从一本优秀的 Hack-Proofing 书中摘录可能会对您有所帮助。

    许多溢出错误是错误的字符串操作的结果。调用如 strcpy() 在复制之前不检查字符串的长度。结果是 可能会发生缓冲区溢出。预计 NULL 终止符将 出席。从某种意义上说,攻击者依靠这个漏洞来利用 机器;然而,这也意味着攻击者注入的缓冲区也必须 不含 NULL 字符。如果攻击者插入一个 NULL 字符, 在插入整个有效负载之前,字符串复制将被终止。

    【讨论】:

    • “strncpy 大大降低了缓冲区溢出攻击的可能性”问题中的代码表明它没有,但是存在认为n 是一种神奇的小精灵尘埃的程序员改进他们的代码。
    【解决方案4】:

    strncpy(dest, src, strlen(src));与 strcpy(dest, src) 相同;所以这里没有区别,但是..

    Strcpy 可能会导致安全漏洞,因为您不知道字符串有多长。聪明的人可以用这个覆盖你服务器上的东西。

    【讨论】:

    • 如果src 不是\0-终止的,那么strncpy(dst, src, strlen(src)) 与普通的strcpy(dst, src) 相比,在安全方面显然没有任何帮助。
    【解决方案5】:

    strn 系列的原因是为了防止你溢出缓冲区。如果您从调用者那里传递数据并且盲目地相信它正确地以空值终止并且不会溢出您将其复制到的缓冲区,那么您将被缓冲区溢出攻击所拥有。

    效率差异可以忽略不计。 strn 系列可能会稍微慢一些,因为它需要不断检查您是否没有溢出。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-05
      • 2011-04-13
      • 2012-06-16
      • 1970-01-01
      • 2011-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多