diff --git a/SConstruct b/SConstruct index 6fe96b402..f736e3ae5 100644 --- a/SConstruct +++ b/SConstruct @@ -817,8 +817,11 @@ static void a(){{ raise SCons.Errors.StopError("Compiler cannot handle tuples of 2 elements.") @_implicit_test def check_poison_valgrind(self,context): - context.Display('%s: checking %s...' % (self.msgprefix, 'whether to use Valgrind poisoning')) - r = self.user_settings.poison == 'valgrind' + ''' +help:add Valgrind annotations; wipe certain freed memory when running under Valgrind +''' + context.Message('%s: checking %s...' % (self.msgprefix, 'whether to use Valgrind poisoning')) + r = 'valgrind' in self.user_settings.poison context.Result(r) if not r: return @@ -831,9 +834,27 @@ static void a(){{ if self.Compile(context, text=text, main=main, msg='whether Valgrind memcheck header works', successflags={'CPPDEFINES' : ['DXX_HAVE_POISON_VALGRIND']}): return True raise SCons.Errors.StopError("Valgrind poison requested, but does not work.") + @_implicit_test + def check_poison_overwrite(self,context): + ''' +help:always wipe certain freed memory +''' + context.Message('%s: checking %s...' % (self.msgprefix, 'whether to use overwrite poisoning')) + r = 'overwrite' in self.user_settings.poison + context.Result(r) + if r: + context.sconf.Define('DXX_HAVE_POISON_OVERWRITE') + return r @_custom_test def _check_poison_method(self,context): - if self.check_poison_valgrind(context): + poison = None + for f in ( + self.check_poison_valgrind, + self.check_poison_overwrite, + ): + if f(context): + poison = True + if poison: context.sconf.Define('DXX_HAVE_POISON') class LazyObjectConstructor: @@ -1029,7 +1050,12 @@ class DXXCommon(LazyObjectConstructor): 'variable': self._enum_variable, 'arguments': ( ('host_platform', 'linux' if sys.platform == 'linux2' else sys.platform, 'cross-compile to specified platform', {'allowed_values' : ['win32', 'darwin', 'linux']}), - ('poison', 'none', 'method for poisoning free memory', {'allowed_values' : ('none', 'valgrind')}), + ), + }, + { + 'variable': ListVariable, + 'arguments': ( + ('poison', 'none', 'method for poisoning free memory', {'names' : ('valgrind', 'overwrite')}), ), }, { diff --git a/common/include/poison.h b/common/include/poison.h index 9b449cb94..9100b589f 100644 --- a/common/include/poison.h +++ b/common/include/poison.h @@ -16,7 +16,8 @@ static inline void DXX_MAKE_MEM_UNDEFINED(T *b, unsigned long l) template static inline void DXX_MAKE_MEM_UNDEFINED(T *b, T *e) { - DXX_MAKE_MEM_UNDEFINED(b, e - b); + unsigned char *bc = reinterpret_cast(b); + DXX_MAKE_MEM_UNDEFINED(bc, reinterpret_cast(e) - bc); } template @@ -24,8 +25,12 @@ static inline void _DXX_POISON_MEMORY_RANGE(T b, T e, const V &v) { #ifdef DXX_HAVE_POISON int store = 0; +#ifdef DXX_HAVE_POISON_OVERWRITE + store |= 1; +#endif #ifdef DXX_HAVE_POISON_VALGRIND - store |= RUNNING_ON_VALGRIND; + if (!store) + store |= RUNNING_ON_VALGRIND; #endif if (!store) return; diff --git a/similar/main/object.cpp b/similar/main/object.cpp index ae2e4bb64..f8e1aa9e8 100644 --- a/similar/main/object.cpp +++ b/similar/main/object.cpp @@ -83,6 +83,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #include "compiler-range_for.h" #include "highest_valid.h" #include "partial_range.h" +#include "poison.h" using std::min; using std::max; @@ -1109,6 +1110,8 @@ objptridx_t obj_create(object_type_t type, ubyte id,vsegptridx_t segnum,const vm // Zero out object structure to keep weird bugs from happening // in uninitialized fields. *obj = {}; + // Tell Valgrind to warn on any uninitialized fields. + DXX_MAKE_MEM_UNDEFINED(&*obj, sizeof(*obj)); obj->signature = obj_get_signature(); obj->type = type; @@ -1252,7 +1255,7 @@ void obj_delete(const vobjptridx_t obj) obj_unlink(obj); Assert(Objects[0].next != 0); - + DXX_MAKE_MEM_UNDEFINED(&*obj, sizeof(*obj)); obj->type = OBJ_NONE; //unused! obj->signature = -1;