为什么在C语言中使用strcpy不安全?

10

我是一个初学者,现在正在学习如何在C语言中复制字符串。

我遇到的问题如下:

每次我尝试使用“strcpy”命令从字符串1复制到字符串2时,Visual Studio 2013都会给出一个错误/警告消息,提示我“strcpy”不安全,并建议我使用strcpy_s代替。

请问为什么使用strcpy是不安全的?有哪些更安全的替代方案?

这是我的代码:

#include<stdio.h>
#include<string.h>
main()
{
    char str1[] = "Copy a string.";
    char str2[15];
    char str3[15];
    int i;

    /* with strcpy() */
    strcpy(str2, str1);
    /* Without strcpy() */
    for (i = 0; str1[i]; i++)
        str3[i] = str1[i];
    str3[i] = '\0';
    /* Display str2 and str3 */
    printf("The content of str2: %s\n", str2);
    printf("The content of str3: %s\n", str3);
    return 0;
}

P.S. 我正在使用 Windows 7 64 位旗舰版上的 Visual Studio 2013 64 位终极版。

非常感谢你的时间!


3
当MSVC编译器告诉你strncpy也不安全时,事情变得有趣了。他们希望你使用strncpy_s,它添加了第二个参数表示大小,并修改了strncpy的标准行为,使得截断的字符串附加一个空终止符。不用说,所有这些_s函数都是非标准的,我通常只需要定义一个特定的预处理器定义来消除那个警告。 - Andon M. Coleman
2
strcpy() 并不是不安全的,微软才是不安全的。C99 标准的支持在哪里?顺便说一句,“不安全”这个词是 PHB 说法,最好忽略它。还有,main 函数的原型是:int main(void)int main(int argc, char **argv) - wildplasser
3
是的,微软也希望采用“拥抱、扩展、灭绝”策略来处理 C 语言。strcpy() 是一个完全安全的函数(不像 gets() 函数)。然而,很多程序员编码水平不佳,然后要求使用更“安全”的编程语言。真是一群胆小鬼。 - EOF
因为C字符串本质上是不安全的:( - Martin James
建议:使用 char str2[sizeofstr1]; 而不是像 15 这样的魔法数字。让编译器计算所需的大小。 - chux - Reinstate Monica
3个回答

12

strcpy函数无法知道目标缓冲区的大小(即没有长度参数),因此使用不当会导致缓冲区溢出并破坏其他内存。这种溢出可能会导致崩溃、奇怪的行为,并且可能会被恶意软件作者利用。

顺便说一下,看一下带有长度参数的strncpy函数。需要注意的一个问题是,如果缓冲区太小,strncpy将无法终止字符串,因此也存在危险。

回答你的评论/问题- 这取决于上下文。如果您知道缓冲区足够大(例如,在前一行中以正确的大小分配了它),请使用strcpy。如果存在任何可能的溢出,则使用strncpy,并确保将缓冲区的最后一个位置设置为null。请注意,“任何可能性”应该非常慷慨地解释-除非前五或六行足以显示安全性,否则请使用strncpy。

另请参见Andon上面关于strncpy_s的评论。最后,如果您使用strcpy,可能需要添加#pragma来抑制该位置的警告。


你认为应该采取什么措施使程序更加健壮?感谢您的回答! - MechAvia
4
请勿将strncpy作为比strcpy更安全的替代方法。请参考这个答案 - r0estir0bbe

3

这是您的原始代码:

int main() {
    char str1[] = "Copy a string.";
    char str2[15];

    strcpy(str2, str1);
}

现在,三天后,你需要编辑这段代码。你已经意识到实际上需要编写消息:"This code is copying a string."
int main() {
    char str1[] = "This code is copying a string.";
    char str2[15];

    strcpy(str2, str1);
}

然而,你现在不小心引入了缓冲区溢出。

strcpy_s 要求传入 str2 的长度参数。这样,即使你不能将整个字符串复制到新的缓冲区中,也不会导致未定义的行为。


1
与 strncpy 和 strcpy_s 不同,strcpy 没有对目标缓冲区进行任何长度检查,这可能会导致堆栈溢出,从而使攻击者能够执行恶意代码,如果被利用,或者仅仅是使您的应用程序崩溃。

1
注意:strncpy也不能保证字符串的终止。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接