Skip to content

Commit ac7c177

Browse files
committed
Merge bitcoin/bitcoin#26654: util: Show descriptive error messages when FileCommit fails
5408a55 Consolidate Win32-specific error formatting (John Moffett) c95a443 Show descriptive error messages when FileCommit fails (John Moffett) Pull request description: Only raw [`errno`](https://en.cppreference.com/w/cpp/error/errno) int values are logged if `FileCommit` fails. These values are implementation-specific, so it makes it harder to debug based on user reports. For instance, bitcoin/bitcoin#26455 (comment) and [another](https://bitcointalk.org/index.php?topic=5182526.0#:~:text=FileCommit%3A%20FlushFileBuffers%20failed%3A%205). Instead, use `SysErrorString` (or the refactored Windows equivalent `Win32ErrorString`) to display both the raw int value and the descriptive message. All other instances in the code I could find where `errno` or (Windows-only) `GetLastError()`/`WSAGetLastError()` are logged use the full descriptive string. For example: https://github.com/bitcoin/bitcoin/blob/1b680948d43b1d39645b9d839a6fa7c6c1786b51/src/util/sock.cpp#L390 https://github.com/bitcoin/bitcoin/blob/1b680948d43b1d39645b9d839a6fa7c6c1786b51/src/util/sock.cpp#L272 https://github.com/bitcoin/bitcoin/blob/7e1007a3c6c9a921c2b60919b84a60eaabfe1c5d/src/netbase.cpp#L515-L516 https://github.com/bitcoin/bitcoin/blob/8ccab65f289e3cce392cbe01d5fc0e7437f51f1e/src/init.cpp#L164 I refactored the Windows formatting code to put it in `syserror.cpp`, as it's applicable to all Win32 API system errors, not just networking errors. To be clear, the Windows API functions `WSAGetLastError()` and `GetLastError()` are currently [equivalent](https://stackoverflow.com/questions/15586224/is-wsagetlasterror-just-an-alias-for-getlasterror). ACKs for top commit: MarcoFalke: lgtm ACK 5408a55 💡 Tree-SHA512: 3921cbac98bd9edaf84d3dd7a43896c7921f144c8ca2cde9bc96d5fb05281f7c55e7cc99db8debf6203b5f916f053025e4fa741f51458fe2c53bb57b0a781027
2 parents 1fde20f + 5408a55 commit ac7c177

File tree

5 files changed

+38
-33
lines changed

5 files changed

+38
-33
lines changed

src/util/fs.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,7 @@ bool FileLock::TryLock()
8181
#else
8282

8383
static std::string GetErrorReason() {
84-
wchar_t* err;
85-
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
86-
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<WCHAR*>(&err), 0, nullptr);
87-
std::wstring err_str(err);
88-
LocalFree(err);
89-
return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(err_str);
84+
return Win32ErrorString(GetLastError());
9085
}
9186

9287
FileLock::FileLock(const fs::path& file)

src/util/fs_helpers.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <tinyformat.h>
1515
#include <util/fs.h>
1616
#include <util/getuniquepath.h>
17+
#include <util/syserror.h>
1718

1819
#include <cerrno>
1920
#include <filesystem>
@@ -120,28 +121,28 @@ std::streampos GetFileSize(const char* path, std::streamsize max)
120121
bool FileCommit(FILE* file)
121122
{
122123
if (fflush(file) != 0) { // harmless if redundantly called
123-
LogPrintf("%s: fflush failed: %d\n", __func__, errno);
124+
LogPrintf("fflush failed: %s\n", SysErrorString(errno));
124125
return false;
125126
}
126127
#ifdef WIN32
127128
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
128129
if (FlushFileBuffers(hFile) == 0) {
129-
LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
130+
LogPrintf("FlushFileBuffers failed: %s\n", Win32ErrorString(GetLastError()));
130131
return false;
131132
}
132133
#elif defined(MAC_OSX) && defined(F_FULLFSYNC)
133134
if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
134-
LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
135+
LogPrintf("fcntl F_FULLFSYNC failed: %s\n", SysErrorString(errno));
135136
return false;
136137
}
137138
#elif HAVE_FDATASYNC
138139
if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
139-
LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
140+
LogPrintf("fdatasync failed: %s\n", SysErrorString(errno));
140141
return false;
141142
}
142143
#else
143144
if (fsync(fileno(file)) != 0 && errno != EINVAL) {
144-
LogPrintf("%s: fsync failed: %d\n", __func__, errno);
145+
LogPrintf("fsync failed: %s\n", SysErrorString(errno));
145146
return false;
146147
}
147148
#endif

src/util/sock.cpp

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@
1515
#include <stdexcept>
1616
#include <string>
1717

18-
#ifdef WIN32
19-
#include <codecvt>
20-
#include <locale>
21-
#endif
22-
2318
#ifdef USE_POLL
2419
#include <poll.h>
2520
#endif
@@ -416,26 +411,12 @@ void Sock::Close()
416411
m_socket = INVALID_SOCKET;
417412
}
418413

419-
#ifdef WIN32
420414
std::string NetworkErrorString(int err)
421415
{
422-
wchar_t buf[256];
423-
buf[0] = 0;
424-
if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
425-
nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
426-
buf, ARRAYSIZE(buf), nullptr))
427-
{
428-
return strprintf("%s (%d)", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);
429-
}
430-
else
431-
{
432-
return strprintf("Unknown error (%d)", err);
433-
}
434-
}
416+
#if defined(WIN32)
417+
return Win32ErrorString(err);
435418
#else
436-
std::string NetworkErrorString(int err)
437-
{
438419
// On BSD sockets implementations, NetworkErrorString is the same as SysErrorString.
439420
return SysErrorString(err);
440-
}
441421
#endif
422+
}

src/util/syserror.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
#include <cstring>
1313
#include <string>
1414

15+
#if defined(WIN32)
16+
#include <windows.h>
17+
#include <locale>
18+
#include <codecvt>
19+
#endif
20+
1521
std::string SysErrorString(int err)
1622
{
1723
char buf[1024];
@@ -33,3 +39,21 @@ std::string SysErrorString(int err)
3339
return strprintf("Unknown error (%d)", err);
3440
}
3541
}
42+
43+
#if defined(WIN32)
44+
std::string Win32ErrorString(int err)
45+
{
46+
wchar_t buf[256];
47+
buf[0] = 0;
48+
if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
49+
nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
50+
buf, ARRAYSIZE(buf), nullptr))
51+
{
52+
return strprintf("%s (%d)", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);
53+
}
54+
else
55+
{
56+
return strprintf("Unknown error (%d)", err);
57+
}
58+
}
59+
#endif

src/util/syserror.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@
1313
*/
1414
std::string SysErrorString(int err);
1515

16+
#if defined(WIN32)
17+
std::string Win32ErrorString(int err);
18+
#endif
19+
1620
#endif // BITCOIN_UTIL_SYSERROR_H

0 commit comments

Comments
 (0)