繁体   English   中英

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

[英]C++ 'strcpy' gives a Warning (C4996)

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

这到底是什么意思?

'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.

此函数 (strcpy) 被认为是不安全的,因为没有边界检查,并且可能导致缓冲区溢出。 (实际上 strcpy 因溢出漏洞而臭名昭著,所有程序员都避免使用它——或者至少应该避免它)。 建议是使用考虑目标缓冲区大小的安全函数以避免溢出。 您也可以使用 strncpy (但要小心!)。 您的代码没有问题,即函数将按您说的方式运行,但尝试提供一个大于目标缓冲区的缓冲区作为输入。 该函数将溢出目标缓冲区。 检查这也链接文本

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

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

你有几个选择。

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

我通常做#3。

由于您正在编写 C++,因此正确的解决方案是在可能的情况下从您的代码中禁止 C 风格的char*字符串,并用std::string (或其他适当的字符串类型)替换它们。

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

由于 VC++ 8 strcpy()和大量其他函数被认为是不安全的,因为它们没有边界检查,如果误用可能会导致缓冲区溢出。

您有两个选择:

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

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

您可以启用安全模板重载 他们将(如果可能)通过使用模板化重载捕获它们来推断使用的缓冲区的长度。 为什么在 Visual C++ 中默认情况下没有启用这对我来说是个谜。

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

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

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

#pragma warning(disable: 4996)

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

如果您已经查看了使用 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
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1 
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1 

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

使用安全模板重载定义包装函数不适用于动态分配的缓冲区,因此这种尝试是徒劳的。
修改源以使用安全替换,或者只是忽略它。

如果代码是自己写的,最好把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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM