From 343318d73ed24b1d94ddeaafa9339c38c947dcbd Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Tue, 25 Oct 2016 12:01:03 +0300 Subject: [PATCH] Add a thread-safe wxSysErrorMsgStr() Implement wxSysErrorMsg's functionality without using static buffers; have the caller provide the buffer. When the caller uses the original API and does not provide a buffer, a static buffer is still used. wxSysErrorMsgStr() returns a wxString. Also use strerror_r() instead of strerror() on platforms other than MSW. --- include/wx/log.h | 4 ++++ interface/wx/log.h | 17 +++++++++++++ src/common/log.cpp | 60 +++++++++++++++++++++++++++++++++------------- 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/include/wx/log.h b/include/wx/log.h index cbc15efde9..3228bed7ff 100644 --- a/include/wx/log.h +++ b/include/wx/log.h @@ -1188,6 +1188,9 @@ WXDLLIMPEXP_BASE unsigned long wxSysErrorCode(); // return the error message for given (or last if 0) error code WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); +// return the error message for given (or last if 0) error code +WXDLLIMPEXP_BASE wxString wxSysErrorMsgStr(unsigned long nErrCode = 0); + // ---------------------------------------------------------------------------- // define wxLog() functions which can be used by application instead of // stdio, iostream &c for log messages for easy redirection @@ -1393,6 +1396,7 @@ public: // Dummy macros to replace some functions. #define wxSysErrorCode() (unsigned long)0 #define wxSysErrorMsg( X ) (const wxChar*)NULL +#define wxSysErrorMsgStr( X ) wxEmptyString // Fake symbolic trace masks... for those that are used frequently #define wxTRACE_OleCalls wxEmptyString // OLE interface calls diff --git a/interface/wx/log.h b/interface/wx/log.h index 7b5dc8de73..b76d734730 100644 --- a/interface/wx/log.h +++ b/interface/wx/log.h @@ -1226,6 +1226,23 @@ unsigned long wxSysErrorCode(); @a errCode is 0 (default), the last error code (as returned by wxSysErrorCode()) is used. + Use this function instead of wxSysErrorMsg(), as the latter one is not + thread-safe. + + @see wxSysErrorCode(), wxLogSysError() + + @header{wx/log.h} +*/ +wxString wxSysErrorMsgStr(unsigned long errCode = 0); + +/** + Returns the error message corresponding to the given system error code. If + @a errCode is 0 (default), the last error code (as returned by + wxSysErrorCode()) is used. + + Use wxSysErrorMsgStr() instead of this function especially in a + multi-threaded application. + @see wxSysErrorCode(), wxLogSysError() @header{wx/log.h} diff --git a/src/common/log.cpp b/src/common/log.cpp index c2828ba8f5..7c1e9e89bb 100644 --- a/src/common/log.cpp +++ b/src/common/log.cpp @@ -48,6 +48,8 @@ // other standard headers #include +#include + #include #include @@ -1055,15 +1057,12 @@ unsigned long wxSysErrorCode() #endif //Win/Unix } -// get error message from system -const wxChar *wxSysErrorMsg(unsigned long nErrCode) +static const wxChar* GetSysErrorMsg(wxChar* szBuf, size_t len, unsigned long nErrCode) { if ( nErrCode == 0 ) nErrCode = wxSysErrorCode(); #if defined(__WINDOWS__) - static wxChar s_szBuf[1024]; - // get error message from system LPVOID lpMsgBuf; if ( ::FormatMessage @@ -1079,8 +1078,8 @@ const wxChar *wxSysErrorMsg(unsigned long nErrCode) { // if this happens, something is seriously wrong, so don't use _() here // for safety - wxSprintf(s_szBuf, wxS("unknown error %lx"), nErrCode); - return s_szBuf; + wxSprintf(szBuf, wxS("unknown error %lx"), nErrCode); + return szBuf; } @@ -1088,34 +1087,61 @@ const wxChar *wxSysErrorMsg(unsigned long nErrCode) // Crashes on SmartPhone (FIXME) if( lpMsgBuf != 0 ) { - wxStrlcpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf)); + wxStrlcpy(szBuf, (const wxChar *)lpMsgBuf, len); LocalFree(lpMsgBuf); // returned string is ended with '\r\n' - bad - size_t len = wxStrlen(s_szBuf); + size_t len = wxStrlen(szBuf); if ( len >= 2 ) { // truncate string - if ( s_szBuf[len - 2] == wxS('\r') ) - s_szBuf[len - 2] = wxS('\0'); + if ( szBuf[len - 2] == wxS('\r') ) + szBuf[len - 2] = wxS('\0'); } } else { - s_szBuf[0] = wxS('\0'); + szBuf[0] = wxS('\0'); } - return s_szBuf; + return szBuf; #else // !__WINDOWS__ + char buffer[1024]; + char *errorMsg = buffer; + +#ifdef _GNU_SOURCE // GNU-specific strerror_r + // GNU's strerror_r has a weird interface -- it doesn't + // necessarily copy anything to the buffer given; use return + // value instead. + errorMsg = strerror_r((int)nErrCode, buffer, sizeof(buffer)); +#else // XSI-compliant strerror_r + strerror_r((int)nErrCode, buffer, sizeof(buffer)); +#endif + + // at this point errorMsg might not point to buffer anymore + szBuf[0] = wxS('\0'); #if wxUSE_UNICODE - static wchar_t s_wzBuf[1024]; - wxConvCurrent->MB2WC(s_wzBuf, strerror((int)nErrCode), - WXSIZEOF(s_wzBuf) - 1); - return s_wzBuf; + wxConvCurrent->MB2WC(szBuf, errorMsg, len - 1); + szBuf[len - 1] = wxS('\0'); #else - return strerror((int)nErrCode); + wxStrlcpy(szBuf, errorMsg, len); #endif + return szBuf; #endif // __WINDOWS__/!__WINDOWS__ } +// get error message from system +const wxChar *wxSysErrorMsg(unsigned long nErrCode) +{ + static wxChar s_szBuf[1024]; + return GetSysErrorMsg(s_szBuf, WXSIZEOF(s_szBuf), nErrCode); +} + +// get error message from system as wxString +wxString wxSysErrorMsgStr(unsigned long nErrCode) +{ + wxChar szBuf[1024]; + return GetSysErrorMsg(szBuf, WXSIZEOF(szBuf), nErrCode); +} + #endif // wxUSE_LOG