Add parameter type checks to printf style functions

gcc supports type checks for printf parameters which can catch some hard
to reproduce bugs. Possible bugs happen when the parameter value is
intepreted differently to the variable value.

Example warnings follow
../library/LuaWrapper.cpp:1011:86: warning: format ‘%llu’ expects argument
    of type ‘long long unsigned int’, but argument 3 has type ‘uint64_t
    {aka long unsigned int}’ [-Wformat=]
../plugins/follow.cpp:159:35: warning: format not a string literal and no
    format arguments [-Wformat-security]
develop
Pauli 2018-06-11 19:20:51 +03:00
parent 8717144f14
commit 8484b5dc8a
5 changed files with 20 additions and 9 deletions

@ -463,7 +463,7 @@ DFhackCExport char * SDL_GetError(void)
} }
static void (*_SDL_SetError)(const char *fmt, ...) = 0; static void (*_SDL_SetError)(const char *fmt, ...) = 0;
DFhackCExport void SDL_SetError(const char *fmt, ...) DFhackCExport void SDL_SetError(const char *fmt, ...) Wformat(printf,1,2)
{ {
char buf[1024]; char buf[1024];
va_list args; va_list args;

@ -106,12 +106,12 @@ namespace DFHack
virtual ~color_ostream(); virtual ~color_ostream();
/// Print a formatted string, like printf /// Print a formatted string, like printf
void print(const char *format, ...); void print(const char *format, ...) Wformat(printf,2,3);
void vprint(const char *format, va_list args); void vprint(const char *format, va_list args) Wformat(printf,2,0);
/// Print a formatted string, like printf, in red /// Print a formatted string, like printf, in red
void printerr(const char *format, ...); void printerr(const char *format, ...) Wformat(printf,2,3);
void vprinterr(const char *format, va_list args); void vprinterr(const char *format, va_list args) Wformat(printf,2,0);
/// Get color /// Get color
color_value color() { return cur_color; } color_value color() { return cur_color; }

@ -191,8 +191,8 @@ namespace DFHack
DFHack::VersionInfo * vinfo; DFHack::VersionInfo * vinfo;
DFHack::Windows::df_window * screen_window; DFHack::Windows::df_window * screen_window;
static void print(const char *format, ...); static void print(const char *format, ...) Wformat(printf,1,2);
static void printerr(const char *format, ...); static void printerr(const char *format, ...) Wformat(printf,1,2);
PluginManager *getPluginManager() { return plug_mgr; } PluginManager *getPluginManager() { return plug_mgr; }

@ -58,3 +58,14 @@ distribution.
#define DFhackCExport extern "C" __declspec(dllexport) #define DFhackCExport extern "C" __declspec(dllexport)
#define DFhackDataExport extern "C" __declspec(dllexport) #define DFhackDataExport extern "C" __declspec(dllexport)
#endif #endif
// Make gcc warn if types and format string don't match for printf
#ifdef __GNUC__
//! Tell GCC about format functions to allow parameter strict type checks
//! \param type The type of function can be printf, scanf, strftime or strfmon
//! \param fmtstr One based position index for format parameter
//! \param vararg One based position index for the first checked parameter
#define Wformat(type, fmtstr, vararg) __attribute__ ((format (type, fmtstr, vararg)))
#else
#define Wformat(type, fmtstr, vararg)
#endif

@ -354,8 +354,8 @@ DFHACK_EXPORT int random_int(int max);
*/ */
DFHACK_EXPORT uint64_t GetTimeMs64(); DFHACK_EXPORT uint64_t GetTimeMs64();
DFHACK_EXPORT std::string stl_sprintf(const char *fmt, ...); DFHACK_EXPORT std::string stl_sprintf(const char *fmt, ...) Wformat(printf,1,2);
DFHACK_EXPORT std::string stl_vsprintf(const char *fmt, va_list args); DFHACK_EXPORT std::string stl_vsprintf(const char *fmt, va_list args) Wformat(printf,1,0);
// Conversion between CP437 and UTF-8 // Conversion between CP437 and UTF-8
DFHACK_EXPORT std::string UTF2DF(const std::string &in); DFHACK_EXPORT std::string UTF2DF(const std::string &in);