C ++'strcpy'给出警告(C4996)

时间:2010-10-25 06:21:02

标签: c++ visual-c++

我收到此警告但所有功能都正常工作。

这究竟意味着什么?

'strcpy': This function or variable may be unsafe. 
Consider using strcpy_s instead. To disable deprecation, 
use _CRT_SECURE_NO_WARNINGS. See online help for details.

10 个答案:

答案 0 :(得分:22)

由于没有边界检查并且可能导致缓冲区溢出,因此该函数(strcpy)被认为是不安全的。 (实际上strcpy对于溢出漏洞是臭名昭着的,并且所有程序员都避免它 - 或者至少应该避免它)。建议是使用安全函数,该函数考虑目标缓冲区的大小以避免溢出。你也可以使用strncpy(但要小心!)。您的代码没有问题,即函数将按照您的说法运行,但尝试将大于目标缓冲区的缓冲区作为输入。该函数将溢出目标缓冲区。同时检查link text

答案 1 :(得分:11)

虽然strcpy是一个常见的字符串函数,但它有一个历史,它是软件中许多错误和安全漏洞的来源(由于缓冲区溢出很容易)。

微软为了在C和C ++中推广更安全的编码,为危险的字符串方法提供了一套替换函数。通常,它们的原始名称后跟_s。因此,strcpy的Microsoft安全版本是警告中建议的strcpy_s。请注意这是Microsoft特有的功能,它并不是无处不在。

你有几个选择。

  1. 如果您不想关心它,请定义_CRT_SECURE_NO_WARNINGS,从而在您的软件中留下安全问题。
  2. 将您的字符串函数替换为安全字符串函数,从而降低您的软件的可移植性
  3. 包装安全字符串函数并在任何地方使用包装器,在Windows平台上提供增强的安全性,并回退到其他平台上的传统版本。包装函数可以通过MACRO或编译函数。
  4. 我通常做#3。

答案 2 :(得分:10)

由于您正在编写C ++,正确的解决方案是尽可能禁止代码中的C风格char*字符串,并将其替换为std::string(或其他适当的字符串类型)。

使用strcpystrcpy_sstrncpy等功能。使用string类的复制构造函数或赋值运算符。或者,如果您确实需要复制缓冲区,请使用std::copy

答案 3 :(得分:8)

由于VC ++ 8 strcpy()和一大堆其他函数are considered to be unsafe,因为它们没有边界检查,如果误用会导致缓冲区溢出。

您有两种选择:

  • 如果你不确定 - 做VC ++所说的并使用“安全”功能。它们将触发一个错误处理程序,如果出现问题将终止你的程序。
  • 如果您知道自己在做什么 - 您知道不会发生任何超限并且所有边缘情况都由您的代码处理 - 在包含CRT标头之前定义_CRT_SECURE_NO_WARNINGS,这将使警告消失。

答案 4 :(得分:4)

该警告基本上是告知您strcpy已弃用,因为复制字符串直到\0很容易导致令人讨厌的问题(缓冲区溢出)。 strcpy仍然存在的原因是它是标准库遗留的一部分,但你应该考虑使用str * _s或strn *函数(它们不仅仅依赖于查找终止\0)。

由于缓冲区溢出不仅与安全问题相关联,而且与相对难以跟踪和修复的错误相关联,因此使用普通的vanilla str *函数不仅通常不受欢迎,而且可能导致人们拒绝您的代码本身不安全的。

更多细节: http://www.safercode.com/blog/2008/11/04/unsafe-functions-in-c-and-their-safer-replacements-strings-part-i.html

答案 5 :(得分:4)

实际上有一种方法可以避免这种警告,仍然使用strcpy,并且是安全的:

您可以启用secure template overloads。它们(如果可能的话)推导出使用模板化重载捕获它们所使用的缓冲区的长度。对我来说,为什么在Visual C ++中默认不启用它是一个谜。

答案 6 :(得分:2)

#pragma warning(disable: 4996)

在代码的第一行使用上面的代码。

答案 7 :(得分:1)

如果您已经了解了使用C ++纯粹技术的优缺点而不是担心,因为您“知道”您的字符串将被终止,那么您也可以在msvc中禁用警告,这类事情:

#ifdef _MSC_VER
  // 4231: nonstandard extension used : 'extern' before template explicit instantiation
  // 4250: dominance
  // 4251: member needs to have dll-interface
  // 4275: base needs to have dll-interface
  // 4660: explicitly instantiating a class that's already implicitly instantiated
  // 4661: no suitable definition provided for explicit template instantiation request
  // 4786: identifer was truncated in debug information
  // 4355: 'this' : used in base member initializer list
  // 4910: '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation
#   pragma warning(disable: 4231 4250 4251 4275 4660 4661 4786 4355 4910)
#endif

答案 8 :(得分:0)

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1 
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1 

在文件的顶部为我工作 (基于其他 SO 用户的回答......但我找不到推荐他/她)

答案 9 :(得分:-1)

使用Secure Template Overloadsdefine wrapper functions对动态分配的缓冲区不起作用,因此这种尝试是徒劳的。
修改源代码以使用安全替换,或者忽略它。

如果代码是自己编写的,最好将strcpy更改为strcpy_s等。 如果模块是从受信任的源导入的,您可以选择忽略该警告。

忽略方法1:项目全局范围:添加_CRT_SECURE_NO_WARNINGS
忽略方法2:忽略特定模块:如果只有一个或两个,那么在包含它们时你可以简单地为这些模块设置警告:

#pragma warning(push)
#pragma warning(disable: 4996)
#include <sapi.h>  //legacy module
#include <sphelper.h> //legacy module
#pragma warning(pop)