Remove use of non-threadsafe strerror
Add helper class to use strerror_r or strerror_s
This commit is contained in:
@@ -125,7 +125,7 @@ void MusicDriver_ExtMidi::DoPlay()
|
|||||||
}
|
}
|
||||||
|
|
||||||
case -1:
|
case -1:
|
||||||
DEBUG(driver, 0, "extmidi: couldn't fork: %s", strerror(errno));
|
DEBUG(driver, 0, "extmidi: couldn't fork: %s", StrErrorDumper().GetLast());
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@@ -90,14 +90,7 @@ const char *NetworkError::AsString() const
|
|||||||
this->message.assign(FS2OTTD(buffer));
|
this->message.assign(FS2OTTD(buffer));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* Make strerror thread safe by locking access to it. There is a thread safe strerror_r, however
|
this->message.assign(StrErrorDumper().Get(this->error));
|
||||||
* the non-POSIX variant is available due to defining _GNU_SOURCE meaning it is not portable.
|
|
||||||
* The problem with the non-POSIX variant is that it does not necessarily fill the buffer with
|
|
||||||
* the error message but can also return a pointer to a static bit of memory, whereas the POSIX
|
|
||||||
* variant always fills the buffer. This makes the behaviour too erratic to work with. */
|
|
||||||
static std::mutex mutex;
|
|
||||||
std::lock_guard<std::mutex> guard(mutex);
|
|
||||||
this->message.assign(strerror(this->error));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return this->message.c_str();
|
return this->message.c_str();
|
||||||
|
@@ -275,7 +275,7 @@ class CrashLogUnix : public CrashLog {
|
|||||||
{
|
{
|
||||||
struct utsname name;
|
struct utsname name;
|
||||||
if (uname(&name) < 0) {
|
if (uname(&name) < 0) {
|
||||||
return buffer + seprintf(buffer, last, "Could not get OS version: %s\n", strerror(errno));
|
return buffer + seprintf(buffer, last, "Could not get OS version: %s\n", StrErrorDumper().GetLast());
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer + seprintf(buffer, last,
|
return buffer + seprintf(buffer, last,
|
||||||
|
@@ -1392,3 +1392,33 @@ public:
|
|||||||
#endif /* defined(WITH_COCOA) && !defined(STRGEN) && !defined(SETTINGSGEN) */
|
#endif /* defined(WITH_COCOA) && !defined(STRGEN) && !defined(SETTINGSGEN) */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const char *StrErrorDumper::Get(int errornum)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (strerror_s(this->buf, lengthof(this->buf), errornum) == 0) {
|
||||||
|
return this->buf;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
struct StrErrorRHelper {
|
||||||
|
static bool Success(char *result) { return true; } ///< GNU-specific
|
||||||
|
static bool Success(int result) { return result == 0; } ///< XSI-compliant
|
||||||
|
|
||||||
|
static const char *GetString(char *result, const char *buffer) { return result; } ///< GNU-specific
|
||||||
|
static const char *GetString(int result, const char *buffer) { return buffer; } ///< XSI-compliant
|
||||||
|
};
|
||||||
|
|
||||||
|
auto result = strerror_r(errornum, this->buf, lengthof(this->buf));
|
||||||
|
if (StrErrorRHelper::Success(result)) {
|
||||||
|
return StrErrorRHelper::GetString(result, this->buf);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
seprintf(this->buf, lastof(this->buf), "Unknown error %d", errornum);
|
||||||
|
return this->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *StrErrorDumper::GetLast()
|
||||||
|
{
|
||||||
|
return this->Get(errno);
|
||||||
|
}
|
||||||
|
@@ -306,4 +306,17 @@ inline bool IsWhitespace(char32_t c)
|
|||||||
char *strcasestr(const char *haystack, const char *needle);
|
char *strcasestr(const char *haystack, const char *needle);
|
||||||
#endif /* strcasestr is available */
|
#endif /* strcasestr is available */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The use of a struct is so that when used as an argument to seprintf/etc, the buffer lives
|
||||||
|
* on the stack with a lifetime which lasts until the end of the statement.
|
||||||
|
* This avoids using a static buffer which is thread-unsafe, or needing to call malloc, which would then nee to be freed.
|
||||||
|
*/
|
||||||
|
struct StrErrorDumper {
|
||||||
|
const char *Get(int errornum);
|
||||||
|
const char *GetLast();
|
||||||
|
|
||||||
|
private:
|
||||||
|
char buf[128];
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* STRING_FUNC_H */
|
#endif /* STRING_FUNC_H */
|
||||||
|
Reference in New Issue
Block a user