簡體   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