【问题标题】:C - Use of strcpy in generalC - 一般使用 strcpy
【发布时间】:2015-06-26 14:33:38
【问题描述】:

我有这段代码:

new->name = zalloc(sizeof(char) * strlen(name) + 1);
if (!new->name)
    goto alloc_failed;
strcpy(new->name, name);

如果 strcpy() 不赞成,即使名称空间是预先分配的,这也是一般用途。只是想知道出于安全目的。最好使用 strncpy() 或 srtlcpy()。

【问题讨论】:

  • strcpystrlcpy 之间的选择是一个意见问题,唯一重要的意见是资助您的薪水或为您的作业评分的人的意见。 OTOH,我想大多数人都会同意strncpy 是一个糟糕的选择,因为它不能保证输出将被 NUL 终止(因此您需要额外的代码来 NUL 终止字符串)。
  • memcpy 在这里更有意义,因为您知道长度

标签: c buffer buffer-overflow strcpy strncpy


【解决方案1】:

您的编码示例有一些小问题:

new->name = zalloc(sizeof(char) * strlen(name) + 1);
if (!new->name)
    goto alloc_failed;
strcpy(new->name, name);

分配的大小计算为sizeof(char) * strlen(name) + 1。如果你坚持乘以sizeof(char),根据定义等于1,你至少应该写:sizeof(char) * (strlen(name) + 1)。除此之外,在此示例中您可以使用 strcpy,但将大小存储在局部变量中并使用 memcpy 会更有效:

{
    size_t size = strlen(name) + 1;
    new->name = zalloc(size);
    if (!new->name)
        goto alloc_failed;
    memcpy(new->name, name, size);
}

另请注意,POSIX 系统有strdup(),它使用malloc 做同样的事情。如果zalloc()malloc() 上的一个瘦包装器,它从单个大小参数分配内存并将其初始化为零,则可以使用strdup() 作为此代码的简单替换。如果是自定义内存分配方案,还需要提供zstrdup(),因为重复字符串在很多C程序中很常见。

另一个关于风格的小评论:如果本地编码约定允许使用 goto 在这里很好,但最好不要使用明显的 C++ 关键字,例如 newdelete 作为普通标识符。

关于strlcpy(),它可能在您的平台上可用也可能不可用,但在其他地方是一个不错的选择。 strncpy() OTOH 最好避免。它是一个标准的 C 函数,但它的语义与 C 库的其他部分不一致,因此经常被误用:

  • 著名的缺点是strncpy() 如果源字符串长于大小参数,则不会在目标末尾添加'\0'snprintf(dest, size, "%s", src); 会这样做,但可能效率不高。

  • 当源字符串比大小参数短时,strncpy 的一个鲜为人知的副作用会发生:目标数组'\0' 填充到末尾。如果目标数组比源数组长很多,使用strncpy() 避免缓冲区溢出是非常低效的。

【讨论】:

    【解决方案2】:

    当您知道可能的数据的最大限制是多少时,您应该使用 strcpy,当它是用户定义时,您应该使用 strncpy。

    你在这个例子中使用 strcpy 没问题。

    【讨论】:

    • strcpy and relatives should not be used anymore。在这个术语中,这个问题是有道理的。 strcpy 至少不应该再使用了。
    • strncpy 比 strcpy 更安全是一个普遍的误解。它不是。它只是将一个问题(缓冲区溢出)换成另一个问题(非空终止字符串)。 strncpy 的大问题是使用它可能会产生非空终止字符缓冲区。这可能会导致危险的错误和漏洞利用。谷歌“strncpy 不安全”。例如:randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already
    • 没有取舍。缓冲区溢出无法在 strcpy 中处理,而可能丢失的 NUL 终止可以通过显式设置缓冲区的最后一个条目轻松添加。所以,你真的想告诉你,两者都有同样的问题吗?
    • @Olaf 这可能似乎合理,但一般来说,边界检查应该只在接口边界上进行,因为根据定义,不断检查所有不那么明显的不变量是过度的.
    • 安全总比抱歉好(是的,我知道原始版本)。对于大多数现代系统来说,这根本不是问题,并且对于大多数代码而言,一些额外的检查对性能的影响不容忽视。安全代码对此更为重要。高度优化的代码已经封装在几个模块中,并且优化肯定是合理的。但是,这应该是有意应用的;默认情况下应该先安全起见,尤其是让新手程序员想到这一点!世界上有足够多的不安全软件。
    猜你喜欢
    • 2014-03-12
    • 2018-11-29
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多