From 674a9213f826d13d17370245f0b7e852b8eb6e9a Mon Sep 17 00:00:00 2001 From: Kp Date: Fri, 15 Jul 2016 03:43:03 +0000 Subject: [PATCH] Add workaround for Win32 wrong type for size_t GCC std::array uses std::size_t for its size_type. On Linux/amd64, `std::size_t` is `unsigned long`. On Win32, `std::size_t` is `unsigned int`. This provokes format string warnings because an unsigned int is passed where the format string declares an unsigned long. On Win32, `unsigned int` and `unsigned long` are the same size, so `unsigned long` could have been used to avoid this problem by maintaining consistency with Linux, but it was not. This may have been an attempt to achieve bug compatibility with Microsoft's types. Add a workaround by defining a macro DXX_PRI_size_type in the style of inttypes.h PRI* macros. Use an SConf test to determine the correct value by inspecting which compilation runs succeed. Currently, Linux needs "l", Win32 needs "", and Win64 needs "I64". --- SConstruct | 94 +++++++++++++++++++++++++++++++++++++++++++++ similar/main/bm.cpp | 8 ++-- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/SConstruct b/SConstruct index d41265c78..fdd6108ce 100644 --- a/SConstruct +++ b/SConstruct @@ -1744,6 +1744,100 @@ help:always wipe certain freed memory poison = True if poison: context.sconf.Define('DXX_HAVE_POISON') + implicit_tests.append(_implicit_test.RecordedTest('check_size_type_long', "assume size_t is formatted as `unsigned long`")) + implicit_tests.append(_implicit_test.RecordedTest('check_size_type_int', "assume size_t is formatted as `unsigned int`")) + implicit_tests.append(_implicit_test.RecordedTest('check_size_type_I64', "assume size_t is formatted as `unsigned I64`")) + @_custom_test + def _check_size_type_format_modifier(self,context,_text=''' +#include +#define DXX_PRI_size_type %s +__attribute_format_printf(1, 2) +void f(const char *, ...); +''',_main=''' + std::size_t s = 0; + f("%" DXX_PRI_size_type, s); +'''): + ''' +The test must declare a custom function to call with this format string. +gcc has hardcoded knowledge about how printf works, but that knowledge +on Mingw64 differs from the processing of +__attribute__((format(printf,...))). Mingw64 requires I64u for +__attribute__((format)) functions, but llu for printf. Mingw32 is +consistent in its use of u. Linux gcc is consistent in its use of +lu. + +-- cut -- +#include +#include +__attribute__((format(printf,1,2))) void f(const char *,...); +void a() { + std::size_t b = 0; + printf("%I64u", b); + f("%I64u", b); + printf("%llu", b); + f("%llu", b); + printf("%lu", b); + f("%lu", b); + printf("%u", b); + f("%u", b); +} +-- cut -- + +$ x86_64-w64-mingw32-g++-5.4.0 -x c++ -S -Wformat -o /dev/null - +: In function 'void a()': +:6:19: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long long unsigned int}' [-Wformat=] +:9:13: warning: unknown conversion type character 'l' in format [-Wformat=] +:9:13: warning: too many arguments for format [-Wformat-extra-args] +:10:17: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka long long unsigned int}' [-Wformat=] +:11:12: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka long long unsigned int}' [-Wformat=] +:12:16: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long long unsigned int}' [-Wformat=] +:13:11: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long long unsigned int}' [-Wformat=] + +$ i686-w64-mingw32-g++-5.4.0 -x c++ -S -Wformat -o /dev/null - +: In function 'void a()': +:7:14: warning: format '%I64u' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=] +:8:18: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=] +:9:13: warning: unknown conversion type character 'l' in format [-Wformat=] +:9:13: warning: too many arguments for format [-Wformat-extra-args] +:10:17: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=] +:11:12: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=] + +$ mingw32-g++-5.4.0 -x c++ -S -Wformat -o /dev/null - +: In function 'void a()': +:6:19: warning: format '%I64u' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=] +:7:14: warning: format '%I64u' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=] +:8:18: warning: unknown conversion type character 'l' in format [-Wformat=] +:8:18: warning: too many arguments for format [-Wformat-extra-args] +:9:13: warning: unknown conversion type character 'l' in format [-Wformat=] +:9:13: warning: too many arguments for format [-Wformat-extra-args] +:10:17: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=] +:11:12: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=] + +$ x86_64-pc-linux-gnu-g++-5.4.0 -x c++ -S -Wformat -o /dev/null - +: In function 'void a()': +:6:19: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=] +:7:14: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=] +:8:18: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=] +:9:13: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=] +:12:16: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=] +:13:11: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=] + +''' + # Test types in order of decreasing probability. + for how in ( + # Linux + ('l', 'size_type_long'), + # Win64 + ('I64', 'size_type_I64'), + # Win32 + ('', 'size_type_int'), + ): + DXX_PRI_size_type = how[0] + f = '"%su"' % DXX_PRI_size_type + if self.Compile(context, text=_text % f, main=_main, msg='whether to format std::size_t with "%%%su"' % DXX_PRI_size_type, calling_function=how[1]): + context.sconf.Define('DXX_PRI_size_type', f) + return + raise SCons.Errors.StopError("C++ compiler rejects all candidate format strings for std::size_t.") @_custom_test def check_strcasecmp_present(self,context,_successflags={'CPPDEFINES' : ['DXX_HAVE_STRCASECMP']}): main = ''' diff --git a/similar/main/bm.cpp b/similar/main/bm.cpp index d5fb2a903..f210271da 100644 --- a/similar/main/bm.cpp +++ b/similar/main/bm.cpp @@ -471,12 +471,12 @@ void bm_read_extra_robots(const char *fname, Mission::descent_version_type type) t = PHYSFSX_readInt(fp); if (N_D2_OBJBITMAPS+t >= ObjBitmaps.size()) - Error("Too many object bitmaps (%d) in <%s>. Max is %lu.", t, fname, ObjBitmaps.size() - N_D2_OBJBITMAPS); + Error("Too many object bitmaps (%d) in <%s>. Max is %" DXX_PRI_size_type "u.", t, fname, ObjBitmaps.size() - N_D2_OBJBITMAPS); bitmap_index_read_n(fp, partial_range(ObjBitmaps, N_D2_OBJBITMAPS, N_D2_OBJBITMAPS + t)); t = PHYSFSX_readInt(fp); if (N_D2_OBJBITMAPPTRS+t >= ObjBitmapPtrs.size()) - Error("Too many object bitmap pointers (%d) in <%s>. Max is %lu.", t, fname, ObjBitmapPtrs.size() - N_D2_OBJBITMAPPTRS); + Error("Too many object bitmap pointers (%d) in <%s>. Max is %" DXX_PRI_size_type "u.", t, fname, ObjBitmapPtrs.size() - N_D2_OBJBITMAPPTRS); range_for (auto &i, partial_range(ObjBitmapPtrs, N_D2_OBJBITMAPPTRS, N_D2_OBJBITMAPPTRS + t)) i = PHYSFSX_readShort(fp); } @@ -537,7 +537,7 @@ void load_robot_replacements(const d_fname &level_name) for (j=0;j= ObjBitmaps.size()) - Error("Object bitmap number (%d) out of range in (%s). Range = [0..%lu].", i, static_cast(level_name), ObjBitmaps.size() - 1); + Error("Object bitmap number (%d) out of range in (%s). Range = [0..%" DXX_PRI_size_type "].", i, static_cast(level_name), ObjBitmaps.size() - 1); bitmap_index_read(fp, ObjBitmaps[i]); } @@ -545,7 +545,7 @@ void load_robot_replacements(const d_fname &level_name) for (j=0;j= ObjBitmapPtrs.size()) - Error("Object bitmap pointer (%d) out of range in (%s). Range = [0..%lu].", i, static_cast(level_name), ObjBitmapPtrs.size() - 1); + Error("Object bitmap pointer (%d) out of range in (%s). Range = [0..%" DXX_PRI_size_type "].", i, static_cast(level_name), ObjBitmapPtrs.size() - 1); ObjBitmapPtrs[i] = PHYSFSX_readShort(fp); } Robot_replacements_loaded = 1;