Message ID | 20230921121312.1301864-8-armbru@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v3,1/7] migration/rdma: Fix save_page method to fail on polling error | expand |
On 21/9/23 14:13, Markus Armbruster wrote: > Variables declared in macros can shadow other variables. Much of the > time, this is harmless, e.g.: > > #define _FDT(exp) \ > do { \ > int ret = (exp); \ > if (ret < 0) { \ > error_report("error creating device tree: %s: %s", \ > #exp, fdt_strerror(ret)); \ > exit(1); \ > } \ > } while (0) > > Harmless shadowing in h_client_architecture_support(): > > target_ulong ret; > > [...] > > ret = do_client_architecture_support(cpu, spapr, vec, fdt_bufsize); > if (ret == H_SUCCESS) { > _FDT((fdt_pack(spapr->fdt_blob))); > [...] > } > > return ret; > > However, we can get in trouble when the shadowed variable is used in a > macro argument: > > #define QOBJECT(obj) ({ \ > typeof(obj) o = (obj); \ > o ? container_of(&(o)->base, QObject, base) : NULL; \ > }) > > QOBJECT(o) expands into > > ({ > ---> typeof(o) o = (o); > o ? container_of(&(o)->base, QObject, base) : NULL; > }) > > Unintended variable name capture at --->. We'd be saved by > -Winit-self. But I could certainly construct more elaborate death > traps that don't trigger it. > > To reduce the risk of trapping ourselves, we use variable names in > macros that no sane person would use elsewhere. Here's our actual > definition of QOBJECT(): > > #define QOBJECT(obj) ({ \ > typeof(obj) _obj = (obj); \ > _obj ? container_of(&(_obj)->base, QObject, base) : NULL; \ > }) > > Works well enough until we nest macro calls. For instance, with > > #define qobject_ref(obj) ({ \ > typeof(obj) _obj = (obj); \ > qobject_ref_impl(QOBJECT(_obj)); \ > _obj; \ > }) > > the expression qobject_ref(obj) expands into > > ({ > typeof(obj) _obj = (obj); > qobject_ref_impl( > ({ > ---> typeof(_obj) _obj = (_obj); > _obj ? container_of(&(_obj)->base, QObject, base) : NULL; > })); > _obj; > }) > > Unintended variable name capture at --->. > > The only reliable way to prevent unintended variable name capture is > -Wshadow. > > One blocker for enabling it is shadowing hiding in function-like > macros like > > qdict_put(dict, "name", qobject_ref(...)) > > qdict_put() wraps its last argument in QOBJECT(), and the last > argument here contains another QOBJECT(). > > Use dark preprocessor sorcery to make the macros that give us this > problem use different variable names on every call. > > Signed-off-by: Markus Armbruster <armbru@redhat.com> > Reviewed-by: Eric Blake <eblake@redhat.com> > --- > include/qapi/qmp/qobject.h | 10 ++++++++-- > include/qemu/atomic.h | 17 ++++++++++++----- > include/qemu/compiler.h | 3 +++ > include/qemu/osdep.h | 27 ++++++++++++++++++++------- > 4 files changed, 43 insertions(+), 14 deletions(-) Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index 9003b71fd3..89b97d88bc 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -45,10 +45,16 @@ struct QObject { struct QObjectBase_ base; }; -#define QOBJECT(obj) ({ \ +/* + * Preprocessor sorcery ahead: use a different identifier for the + * local variable in each expansion, so we can nest macro calls + * without shadowing variables. + */ +#define QOBJECT_INTERNAL(obj, _obj) ({ \ typeof(obj) _obj = (obj); \ - _obj ? container_of(&(_obj)->base, QObject, base) : NULL; \ + _obj ? container_of(&_obj->base, QObject, base) : NULL; \ }) +#define QOBJECT(obj) QOBJECT_INTERNAL((obj), MAKE_IDENTFIER(_obj)) /* Required for qobject_to() */ #define QTYPE_CAST_TO_QNull QTYPE_QNULL diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index d95612f7a0..f1d3d1702a 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -157,13 +157,20 @@ smp_read_barrier_depends(); #endif -#define qatomic_rcu_read(ptr) \ - ({ \ +/* + * Preprocessor sorcery ahead: use a different identifier for the + * local variable in each expansion, so we can nest macro calls + * without shadowing variables. + */ +#define qatomic_rcu_read_internal(ptr, _val) \ + ({ \ qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ - typeof_strip_qual(*ptr) _val; \ - qatomic_rcu_read__nocheck(ptr, &_val); \ - _val; \ + typeof_strip_qual(*ptr) _val; \ + qatomic_rcu_read__nocheck(ptr, &_val); \ + _val; \ }) +#define qatomic_rcu_read(ptr) \ + qatomic_rcu_read_internal((ptr), MAKE_IDENTFIER(_val)) #define qatomic_rcu_set(ptr, i) do { \ qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index a309f90c76..03236d830c 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -37,6 +37,9 @@ #define tostring(s) #s #endif +/* Expands into an identifier stemN, where N is another number each time */ +#define MAKE_IDENTFIER(stem) glue(stem, __COUNTER__) + #ifndef likely #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 2897720fac..a80f49d1ab 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -383,19 +383,28 @@ void QEMU_ERROR("code path is reachable") * determined by the pre-processor instead of the compiler, you'll * have to open-code it. Sadly, Coverity is severely confused by the * constant variants, so we have to dumb things down there. + * + * Preprocessor sorcery ahead: use different identifiers for the local + * variables in each expansion, so we can nest macro calls without + * shadowing variables. */ -#undef MIN -#define MIN(a, b) \ +#define MIN_INTERNAL(a, b, _a, _b) \ ({ \ typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ _a < _b ? _a : _b; \ }) -#undef MAX -#define MAX(a, b) \ +#undef MIN +#define MIN(a, b) \ + MIN_INTERNAL((a), (b), MAKE_IDENTFIER(_a), MAKE_IDENTFIER(_b)) + +#define MAX_INTERNAL(a, b, _a, _b) \ ({ \ typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ _a > _b ? _a : _b; \ }) +#undef MAX +#define MAX(a, b) \ + MAX_INTERNAL((a), (b), MAKE_IDENTFIER(_a), MAKE_IDENTFIER(_b)) #ifdef __COVERITY__ # define MIN_CONST(a, b) ((a) < (b) ? (a) : (b)) @@ -416,14 +425,18 @@ void QEMU_ERROR("code path is reachable") /* * Minimum function that returns zero only if both values are zero. * Intended for use with unsigned values only. + * + * Preprocessor sorcery ahead: use different identifiers for the local + * variables in each expansion, so we can nest macro calls without + * shadowing variables. */ -#ifndef MIN_NON_ZERO -#define MIN_NON_ZERO(a, b) \ +#define MIN_NON_ZERO_INTERNAL(a, b, _a, _b) \ ({ \ typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ _a == 0 ? _b : (_b == 0 || _b > _a) ? _a : _b; \ }) -#endif +#define MIN_NON_ZERO(a, b) \ + MIN_NON_ZERO_INTERNAL((a), (b), MAKE_IDENTFIER(_a), MAKE_IDENTFIER(_b)) /* * Round number down to multiple. Safe when m is not a power of 2 (see