我应该在 MSVC - C 上使用安全版本的 POSIX 函数吗

发布于 2024-09-08 19:18:08 字数 562 浏览 4 评论 0原文

我正在编写一些 C 代码,预计可以在多个编译器上编译(至少在 MSVCGCC 上)。由于我是 C 初学者,我打开了所有警告,并将警告视为错误(GCC 中的 -Werror 和 MSVC 中的 /WX),以防止我愚蠢的错误。

当我在 MSVC 上编译一些使用 strcpy 的代码时,我收到类似警告,

警告 C4996: 'strcpy': 此函数或变量可能不安全。考虑使用 strcpy_s 代替。要禁用弃用,请使用 _CRT_SECURE_NO_WARNINGS。有关详细信息,请参阅在线帮助。

我有点困惑。 MSVC 上不推荐使用许多常见功能。在 Windows 上我应该使用这个安全版本吗?如果是,我应该将 strcpy 包装起来,比如“

my_strcpy()
{
#ifdef WIN32
 // use strcpy_s
#ELSE
 // use strcpy    
}

有什么想法吗?”

I am writing some C code which is expected to compile on multiple compilers (at least on MSVC and GCC). Since I am beginner in C, I have all warnings turned on and warnings are treated as errors (-Werror in GCC & /WX in MSVC) to prevent me from making silly mistakes.

When I compiled some code that uses strcpy on MSVC, I get warning like,

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.

I am bit confused. Lot of common functions are deprecated on MSVC. Should I use this secured version when on Windows? If yes, should I wrap strcpy something like,

my_strcpy()
{
#ifdef WIN32
 // use strcpy_s
#ELSE
 // use strcpy    
}

Any thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

生生漫 2024-09-15 19:18:08

每当您在非恒定大小的缓冲区之间移动数据时,您都必须(喘息!天哪!)实际上思考它是否适合。使用声称“安全”的函数(例如 MS 特定的 strcpy_s 或 BSD strlcpy)将保护您免受某些明显的缓冲区溢出的影响条件,但不会保护您免受字符串截断导致的错误的影响。它也不会保护您在计算必要的缓冲区大小时免受整数溢出的影响。

除非您是处理 C 字符串的专家,否则我建议您忘记特殊函数并注释将执行可变长度/位置写入的代码的每一行,并说明您如何知道的理由,在在程序中,您要使用的长度/偏移量在缓冲区大小的范围内。对对大小/偏移执行算术的行也执行此操作 - 记录您如何知道算术不会溢出,如果您发现自己不知道,则添加溢出测试。

另一种方法是将所有字符串处理完全包装在一个字符串对象中,该对象将缓冲区的长度与字符串一起存储,并在需要放大字符串时自动重新分配,然后仅使用 const char * 当您需要将字符串传递给系统函数或其他库时,用于对字符串进行只读访问。这将牺牲您对 C 的期望性能的很大一部分,但它将帮助您确保不会犯错误。只是不要走极端。无需在字符串包装器中重复诸如 strchrstrstr 等内容。只需提供复制字符串对象、连接它们并截断它们的方法,然后使用对 const char * 进行操作的现有库函数,您几乎可以做任何您想做的事情。

Whenever you move data between non-constant-size buffers, you have to (gasp! omg!) actually think about whether it fits. Using functions (like the MS-specific strcpy_s or the BSD strlcpy) that purport to be "safe" will protect you from some obvious buffer overflow conditions, but won't protect you from the bugs that result from string truncation. It also won't protect you from integer overflows in computing the necessary sizes of buffers.

Unless you're an expert dealing with C strings, I would recommend forgetting about special functions and commenting every line of your code that will perform variable-length/position writes with a justification for how you know, at this point in the program, that the length/offset you're about to use is within the bounds of the size of the buffer. Do this for lines where you perform arithmetic on sizes/offsets too - document how you know that the arithmetic will not overflow, and add tests for overflow if you find you don't know.

Another approach is to completely wrap all your string handling in a string object that stores the length of the buffer along with the string and automatically reallocates when a string needs to be enlarged, and then only use const char * for read-only access to strings when you need to pass them to system functions or other libraries. This will sacrifice a good bit of the performance you'd expect from C, but it will help you ensure that you don't make mistakes. Just don't take it to the extreme. There's no need to duplicate stuff like strchr, strstr, etc. in your string wrapper. Just provide methods to duplicate string objects, concatenate them, and truncate them, and then with the existing library functions that operate on const char * you can do just about anything you'd want to.

暗地喜欢 2024-09-15 19:18:08

SO 上有很多关于这个话题的讨论。我确信,像 strncpy、strlcpy 之类的常见嫌疑人会再次出现在这里。只需在搜索框中输入“strcpy”并阅读一些较长的线程即可获得概述。

我的建议是:无论您的最终选择是什么,最好遵循 DRY 原则并继续像 my_strcpy() 示例中那样执行。不要在代码中到处乱扔原始调用,使用包装器并将它们集中在您自己的字符串处理库中。这将减少总体代码(样板文件),并且如果您以后改变主意,您可以在一个中心位置进行修改。

当然,这会带来一些其他的麻烦,特别是对于初学者来说:内存处理责任和界面设计。两者都是一个独立的主题,5 个人会给你 10 条如何做的建议。中央库通常具有很好的效果,它会强制执行一个决策,您将在整个代码库中遵循该决策,而不是在模块 A 中使用方法 a,在模块 B 中使用方法 b,从而在尝试将 A 与 B 连接时给您带来麻烦。 ..

There are lots and lots of discussions about this topic here on SO. The usual suspects like strncpy, strlcpy and whatever will pop up here again, I'm sure. Just type "strcpy" in the search box and read some of the longer threads to get an overview.

My advice is: Whatever your final choice will be, it is a good idea to follow the DRY principle and continue to do it as in your example of my_strcpy(). Don't throw the raw calls all over your code, use wrappers and centralize them in your own string handling library. This will reduce overall code (boilerplate), and you have one central location to make modifications, if you change your mind later.

Of course this opens up some other cans of worms, especially for a beginner: Memory handling responsibility and interface design. Both a topic on its own, and 5 people will give you 10 suggestions of how to do it. A central library usually has the nice effect that it enforces a decision, which you will follow throughout your whole codebase, instead of using method a in module A and method b in module B, causing you trouble when you try to connect A with B...

原野 2024-09-15 19:18:08

我倾向于使用更安全的函数 snprintf †,它在两个平台上都可用,而不是根据平台使用不同的路径。您将需要使用定义来防止 MSVC 上出现警告。

†​​ 虽然可能稍微不太安全 - 它会返回一个错误时不是以 null 结尾的字符串,因此您必须检查返回值,但它不会导致缓冲区溢出。

I would tend to use the safer function snprintf † which is available on both platforms rather than having different paths depending on platform. You will need to use the define to prevent the warnings on MSVC.

† though possibly slightly less safer - it will return a string which is not nul-terminated on error, so you must check the return, but it won't cause a buffer overflow.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文