C++ 为什么我不能使用 strerror?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/900338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why can't I use strerror?
提问by JamieH
I'm porting some code to Windows, and the Microsoft compiler (Visual C++ 8) is telling me that strerror()
is unsafe.
我正在将一些代码移植到 Windows,而 Microsoft 编译器 (Visual C++ 8) 告诉我这strerror()
是不安全的。
Putting aside the annoyance factor in all the safe string stuff from Microsoft, I can actually see that some of the deprecated functions are dangerous. But I can't understand what could be wrong with strerror()
. It takes a code (int
), and returns the corresponding string, or the empty string if that code is not known.
撇开微软所有安全字符串内容中的烦恼因素,我实际上可以看到一些已弃用的函数是危险的。但我无法理解strerror()
. 它接受一个代码 ( int
),并返回相应的字符串,如果该代码未知,则返回空字符串。
Where is the danger?
危险在哪里?
Is there a good alternative in C?
在 C 中有一个好的选择吗?
Is there a good alternative in C++?
C++ 中是否有好的替代方案?
[edit]
[编辑]
Having had some good answers, and now understanding that some implementations may be crazy enough to actually write to a common shared buffer - unsafe to reentrancy within a single-thread, never mind between threads! - my question stops being "Why can't I use it, and what are the alternatives?" to "Are there any decent, succinct alternatives in C and/or C++?"
有了一些很好的答案,现在明白了一些实现可能会疯狂到实际写入公共共享缓冲区 - 在单线程内重入是不安全的,更不用说线程之间了!- 我的问题不再是“为什么我不能使用它,还有什么替代方法?” “在 C 和/或 C++ 中是否有任何体面、简洁的替代方案?”
Thanks in advance
提前致谢
采纳答案by dfa
strerror
is deprecated because it's not thread-safe. strerror
works on an internal static buffer, which may be overwritten by other, concurrent threads. You should use a secure variant called strerror_s
.
strerror
已弃用,因为它不是线程安全的。strerror
在内部静态缓冲区上工作,该缓冲区可能会被其他并发线程覆盖。您应该使用名为strerror_s
.
The secure variant requires that the buffer size be passed to the function in order to validate that the buffer is large enough before writing to it, helping to avoid buffer overruns that could allow malicious code to execute.
安全变体要求将缓冲区大小传递给函数,以便在写入缓冲区之前验证缓冲区是否足够大,从而有助于避免可能允许恶意代码执行的缓冲区溢出。
回答by dwc
strerror
by itself is not unsafe. In the olden days before threading it simply wasn't a problem. With threads, two or more threads could call strerror
leaving the returned buffer in an undefined state. For single threaded programs it shouldn't hurt to use strerror
unless they're playing some weird games in libc, like common memory for all apps in a DLL.
strerror
本身并不是不安全的。在穿线之前的过去,它根本不是问题。对于线程,两个或多个线程可以调用strerror
将返回的缓冲区保持在未定义状态。对于单线程程序,strerror
除非他们在 libc 中玩一些奇怪的游戏,否则使用它应该不会有什么坏处,比如 DLL 中所有应用程序的公共内存。
To address this there's a new interface to the same functionality:
为了解决这个问题,有一个相同功能的新接口:
int strerror_r(int errnum, char *buf, size_t buflen);
Note that the caller provides the buffer space and the buffer size. This solves the issue. Even for single threaded applications you might as well use it. It won't hurt a bit, and you might as well get used to doing it the safer way.
请注意,调用方提供了缓冲区空间和缓冲区大小。这解决了这个问题。即使对于单线程应用程序,您也可以使用它。它不会受到一点伤害,您不妨习惯于以更安全的方式进行。
NOTE: the above prototype is the XSI spec. It may vary per platform or with compiler options or #define
symbols. GNU, for instance, makes that or their own version available depending on a #define
注意:上述原型是 XSI 规范。它可能因平台或编译器选项或#define
符号而异。例如,GNU 使该版本或它们自己的版本可用,具体取决于#define
回答by Bastien Léonard
Having had some good answers, and now understanding that some implementations may be crazy enough to actually write to a common shared buffer - unsafe to reentrancy within a single-thread, never mind between threads! - my question stops being "Why can't I use it, and what are the alternatives?" to "Are there any decent, succinct alternatives in C and/or C++?"
有了一些很好的答案,现在明白了一些实现可能会疯狂到实际写入公共共享缓冲区 - 在单线程内重入是不安全的,更不用说线程之间了!- 我的问题不再是“为什么我不能使用它,还有什么替代方法?” “在 C 和/或 C++ 中是否有任何体面、简洁的替代方案?”
Posix specifies strerror_r()
, and on Windows you can use strerror_s()
, which is a bit different but has the same goal. I do this:
Posix 指定strerror_r()
,并且在 Windows 上您可以使用strerror_s()
,这有点不同但具有相同的目标。我这样做:
#define BAS_PERROR(msg, err_code)\
bas_perror(msg, err_code, __FILE__, __LINE__)
void bas_perror (const char* msg, int err_code, const char* filename,
unsigned long line_number);
void
bas_perror (const char* usr_msg, int err_code, const char* filename,
unsigned long line_number)
{
char sys_msg[64];
#ifdef _WIN32
if ( strerror_s(sys_msg, sizeof sys_msg, err_code) != 0 )
{
strncpy(sys_msg, "Unknown error", taille);
sys_msg[sizeof sys_msg - 1] = 'Thread #1:
char * error = strerror(1);
Thread #2
char * error = strerror(2);
printf(error);
';
}
#else
if ( strerror_r(err_code, sys_msg, sizeof sys_msg) != 0 )
{
strncpy(sys_msg, "Unknown error", sizeof sys_msg);
sys_msg[sizeof sys_msg - 1] = '/* Return a string describing the errno code in ERRNUM.
The storage is good only until the next call to strerror.
Writing to the storage causes undefined behavior. */
libc_freeres_ptr (static char *buf);
';
}
#endif
fprintf(stderr, "%s: %s (debug information: file %s, at line %lu)\n",
usr_msg, sys_msg, filename, line_number);
}
I wrote this function because Posix threads functions don't modify errno
, they return an error code instead. So this function is basically the same as perror()
, except that it allows you to provide an error code other than errno
, and also displays some debugging information. You can adapt it to your need.
我写这个函数是因为 Posix 线程函数不会修改errno
,而是返回错误代码。所以这个功能与 基本相同perror()
,只是它允许您提供除 之外的错误代码errno
,并且还显示一些调试信息。您可以根据需要调整它。
回答by beef2k
You can not rely on the string that is returned by strerror()
because it may change with the next call to the function. The previously returned values may become obsolete then. Especially in multi-threaded environments, you can not ensure that the string is valid when you access it.
您不能依赖由 返回的字符串,strerror()
因为它可能会随着下次调用该函数而改变。以前返回的值可能会过时。尤其是在多线程环境下,访问时无法保证字符串有效。
Imagine this:
想象一下:
std::string errstr = stlsoft::error_desc(errno);
Depending on the implementation of strerror()
, this code prints out the error code for error code 2, not for error code 1.
根据 的实现strerror()
,此代码打印出错误代码 2 的错误代码,而不是错误代码 1。
回答by liuyang1
I understand other answer, but I think showing with code is more clear.
我理解其他答案,但我认为用代码显示更清楚。
check glibc's implementation (we should get similar code in MS lib)
检查 glibc 的实现(我们应该在 MS lib 中得到类似的代码)
##代码##When the errnum
is not kind of known error, it have to generate string like "Unknown error 41". This string is NOT constant, but generate to an allocated buffer. And the buf
is global var. so its content may change when call strerror
again with lock. That's why it's thread-unsafe.
当errnum
不是已知错误时,它必须生成像“未知错误 41”这样的字符串。该字符串不是常量,而是生成到分配的缓冲区。并且buf
是全局变量。所以当strerror
再次使用锁调用时它的内容可能会改变。这就是为什么它是线程不安全的。
On the other hand, strerror_r(int errnum, char *buf, size_t buflen)
, it generate the error string to the argument buf
. so there is NO global resource now. That's why it's thread-safe.
另一方面,strerror_r(int errnum, char *buf, size_t buflen)
它为参数生成错误字符串buf
。所以现在没有全球资源。这就是为什么它是线程安全的。
ref: https://github.com/liuyang1/glibc/blob/master/string/strerror.c#L23-L26
参考:https: //github.com/liuyang1/glibc/blob/master/string/strerror.c#L23-L26
回答by dcw
For a succinct wrapper, you can use STLSoft's stlsoft::error_desc
, as in:
对于简洁的包装器,您可以使用STLSoft的stlsoft::error_desc
,如下所示:
Looking at the code, it seems that it's implemented in terms of strerror()
, which means it'll be safe for reentrancy within a thread (i.e. if used multiple times within a given statement), but it does not address the multithreading problem.
查看代码,它似乎是根据 实现的strerror()
,这意味着在一个线程内重入是安全的(即如果在给定语句中多次使用),但它没有解决多线程问题。
They seem to operate pretty rapid release cycles for defects, so you could try requesting a mod?
他们似乎对缺陷的发布周期非常快,所以你可以尝试请求一个 mod?
回答by Thomas L Holaday
Although I do not know Microsoft's reasons, I note that strerror returns a non-const char *, which means that there is a risk that some Merry Prankster has called strerror before you did and modified the message.
虽然我不知道微软的原因,但我注意到 strerror 返回一个非常量字符 *,这意味着存在一些风险,某些 Merry Prankster 在您之前调用了 strerror 并修改了消息。