diff options
Diffstat (limited to 'src/util.h')
| -rw-r--r-- | src/util.h | 44 |
1 files changed, 34 insertions, 10 deletions
| @@ -14,7 +14,9 @@ typedef unsigned long long uint64; | |||
| 14 | #define for if (false) ; else for | 14 | #define for if (false) ; else for |
| 15 | #endif | 15 | #endif |
| 16 | 16 | ||
| 17 | #ifndef _MSC_VER | 17 | // MinGW already provides __forceinline for MSVC compatibility, so defining it |
| 18 | // unconditionally warned ten times per build once -w was removed. | ||
| 19 | #if !defined(_MSC_VER) && !defined(__forceinline) | ||
| 18 | #define __forceinline inline | 20 | #define __forceinline inline |
| 19 | #endif | 21 | #endif |
| 20 | 22 | ||
| @@ -40,17 +42,17 @@ typedef unsigned long long uint64; | |||
| 40 | #endif | 42 | #endif |
| 41 | #define snprintf my_snprintf | 43 | #define snprintf my_snprintf |
| 42 | 44 | ||
| 45 | // One definition for every target. The MSVCRT branch that used to sit here | ||
| 46 | // produced "I64d", which is the specifier that segfaults on glibc (issue #5) -- | ||
| 47 | // and it was pointless besides: this build targets UCRT, which accepts the C99 | ||
| 48 | // forms, and the rest of the tree already prints int64 with %lld on Windows. | ||
| 49 | // Keeping one spelling everywhere is also what lets the format attributes below | ||
| 50 | // use a single archetype, so a bad specifier fails the build on both platforms. | ||
| 43 | #ifndef PRId64 | 51 | #ifndef PRId64 |
| 44 | #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MSVCRT__) | ||
| 45 | #define PRId64 "I64d" | ||
| 46 | #define PRIu64 "I64u" | ||
| 47 | #define PRIx64 "I64x" | ||
| 48 | #else | ||
| 49 | #define PRId64 "lld" | 52 | #define PRId64 "lld" |
| 50 | #define PRIu64 "llu" | 53 | #define PRIu64 "llu" |
| 51 | #define PRIx64 "llx" | 54 | #define PRIx64 "llx" |
| 52 | #endif | 55 | #endif |
| 53 | #endif | ||
| 54 | 56 | ||
| 55 | // This is needed because the foreach macro can't get over the comma in pair<t1, t2> | 57 | // This is needed because the foreach macro can't get over the comma in pair<t1, t2> |
| 56 | #define PAIRTYPE(t1, t2) pair<t1, t2> | 58 | #define PAIRTYPE(t1, t2) pair<t1, t2> |
| @@ -102,10 +104,30 @@ void LogPrintDedup(const char* category, const char* file, int line, const std:: | |||
| 102 | #define LogPrint(category, ...) \ | 104 | #define LogPrint(category, ...) \ |
| 103 | do { if (LogAcceptsCategory(category)) LogPrintDedup((category), __FILE__, __LINE__, strprintf(__VA_ARGS__)); } while (0) | 105 | do { if (LogAcceptsCategory(category)) LogPrintDedup((category), __FILE__, __LINE__, strprintf(__VA_ARGS__)); } while (0) |
| 104 | 106 | ||
| 107 | // Every format string in this project goes through one of the four functions | ||
| 108 | // below -- `printf` itself is remapped to OutputDebugStringF just above, and | ||
| 109 | // snprintf to my_snprintf. None of them carried a format attribute, and GCC | ||
| 110 | // only checks format strings for functions it knows are printf-like, so | ||
| 111 | // -Wformat had nothing to inspect and the whole tree was unchecked. That is | ||
| 112 | // how `%I64d` (MSVC-only, and a segfault on glibc) survived in | ||
| 113 | // CTxOut::ToString until it crashed a node mid-sync -- see issue #5. | ||
| 114 | // | ||
| 115 | // gnu_printf on both platforms, deliberately. MinGW's other option, ms_printf, | ||
| 116 | // models the legacy msvcrt: it rejects %zu, which this tree uses and UCRT | ||
| 117 | // supports, and it accepts %I64d, which is the specifier that crashes on glibc. | ||
| 118 | // It would give false positives where the code is right and stay silent where it | ||
| 119 | // is dangerous. gnu_printf describes UCRT's C99 behaviour accurately, so one | ||
| 120 | // archetype covers both builds and a bad specifier fails either one. | ||
| 121 | #if defined(__GNUC__) | ||
| 122 | #define BF_FORMAT(fmt, args) __attribute__((format(gnu_printf, fmt, args))) | ||
| 123 | #else | ||
| 124 | #define BF_FORMAT(fmt, args) | ||
| 125 | #endif | ||
| 126 | |||
| 105 | void RandAddSeed(bool fPerfmon=false); | 127 | void RandAddSeed(bool fPerfmon=false); |
| 106 | int my_snprintf(char* buffer, size_t limit, const char* format, ...); | 128 | int my_snprintf(char* buffer, size_t limit, const char* format, ...) BF_FORMAT(3, 4); |
| 107 | string strprintf(const char* format, ...); | 129 | string strprintf(const char* format, ...) BF_FORMAT(1, 2); |
| 108 | bool error(const char* format, ...); | 130 | bool error(const char* format, ...) BF_FORMAT(1, 2); |
| 109 | void PrintException(std::exception* pex, const char* pszThread); | 131 | void PrintException(std::exception* pex, const char* pszThread); |
| 110 | void ParseString(const string& str, char c, vector<string>& v); | 132 | void ParseString(const string& str, char c, vector<string>& v); |
| 111 | string FormatMoney(int64 n, bool fPlus=false); | 133 | string FormatMoney(int64 n, bool fPlus=false); |
| @@ -266,6 +288,8 @@ void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSp | |||
| 266 | // Forward declaration -- defined in main.cpp | 288 | // Forward declaration -- defined in main.cpp |
| 267 | string GetAppDir(); | 289 | string GetAppDir(); |
| 268 | 290 | ||
| 291 | inline int OutputDebugStringF(const char* pszFormat, ...) BF_FORMAT(1, 2); | ||
| 292 | |||
| 269 | inline int OutputDebugStringF(const char* pszFormat, ...) | 293 | inline int OutputDebugStringF(const char* pszFormat, ...) |
| 270 | { | 294 | { |
| 271 | #if 1 // debug.log always enabled | 295 | #if 1 // debug.log always enabled |