From: Markus Armbruster <armbru@redhat.com>
To: qemu-devel@nongnu.org
Cc: stefanha@redhat.com, "Eric Blake" <eblake@redhat.com>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>
Subject: [PULL 07/56] qobject atomics osdep: Make a few macros more hygienic
Date: Fri, 29 Sep 2023 10:50:04 +0200 [thread overview]
Message-ID: <20230929085053.2789105-8-armbru@redhat.com> (raw)
In-Reply-To: <20230929085053.2789105-1-armbru@redhat.com>
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>
Message-ID: <20230921121312.1301864-8-armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
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(-)
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 7fda29b445..7f1bbbf05f 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 e4a4eb2d61..18b940db75 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
--
2.41.0
next prev parent reply other threads:[~2023-09-29 8:54 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-29 8:49 [PULL 00/56] -Wshadow=local patches patches for 2023-09-29 Markus Armbruster
2023-09-29 8:49 ` [PULL 01/56] migration/rdma: Fix save_page method to fail on polling error Markus Armbruster
2023-09-29 8:49 ` [PULL 02/56] migration: Clean up local variable shadowing Markus Armbruster
2023-09-29 8:50 ` [PULL 03/56] ui: " Markus Armbruster
2023-09-29 8:50 ` [PULL 04/56] block/dirty-bitmap: " Markus Armbruster
2023-09-29 8:50 ` [PULL 05/56] block/vdi: " Markus Armbruster
2023-09-29 8:50 ` [PULL 06/56] block: " Markus Armbruster
2023-09-29 8:50 ` Markus Armbruster [this message]
2023-09-29 8:50 ` [PULL 08/56] tcg: " Markus Armbruster
2023-09-29 8:50 ` [PULL 09/56] target/arm/tcg: " Markus Armbruster
2023-09-29 8:50 ` [PULL 10/56] target/arm/hvf: " Markus Armbruster
2023-09-29 8:50 ` [PULL 11/56] target/mips: " Markus Armbruster
2023-09-29 8:50 ` [PULL 12/56] target/m68k: " Markus Armbruster
2023-09-29 8:50 ` [PULL 13/56] target/tricore: " Markus Armbruster
2023-09-29 8:50 ` [PULL 14/56] hw/arm/armv7m: " Markus Armbruster
2023-09-29 8:50 ` [PULL 15/56] hw/arm/virt: " Markus Armbruster
2023-09-29 8:50 ` [PULL 16/56] hw/arm/allwinner: " Markus Armbruster
2023-09-29 8:50 ` [PULL 17/56] hw/m68k: " Markus Armbruster
2023-09-29 8:50 ` [PULL 18/56] hw/microblaze: " Markus Armbruster
2023-09-29 8:50 ` [PULL 19/56] hw/nios2: " Markus Armbruster
2023-09-29 8:50 ` [PULL 20/56] net/eth: " Markus Armbruster
2023-09-29 8:50 ` [PULL 21/56] crypto/cipher-gnutls.c: " Markus Armbruster
2023-09-29 8:50 ` [PULL 22/56] util/vhost-user-server: " Markus Armbruster
2023-09-29 8:50 ` [PULL 23/56] linux-user/strace: " Markus Armbruster
2023-09-29 8:50 ` [PULL 24/56] sysemu/device_tree: " Markus Armbruster
2023-09-29 8:50 ` [PULL 25/56] softmmu/memory: " Markus Armbruster
2023-09-29 8:50 ` [PULL 26/56] softmmu/physmem: " Markus Armbruster
2023-09-29 8:50 ` [PULL 27/56] hw/core/machine: " Markus Armbruster
2023-09-29 8:50 ` [PULL 28/56] hw/intc/openpic: " Markus Armbruster
2023-09-29 8:50 ` [PULL 29/56] hw/ppc: Clean up local variable shadowing in _FDT helper routine Markus Armbruster
2023-09-29 8:50 ` [PULL 30/56] pnv/psi: Clean up local variable shadowing Markus Armbruster
2023-09-29 8:50 ` [PULL 31/56] spapr: Clean up local variable shadowing in spapr_dt_cpus() Markus Armbruster
2023-09-29 8:50 ` [PULL 32/56] spapr: Clean up local variable shadowing in spapr_init_cpus() Markus Armbruster
2023-09-29 8:50 ` [PULL 33/56] spapr: Clean up local variable shadowing in spapr_get_fw_dev_path() Markus Armbruster
2023-09-29 8:50 ` [PULL 34/56] spapr/drc: Clean up local variable shadowing in rtas_ibm_configure_connector() Markus Armbruster
2023-09-29 8:50 ` [PULL 35/56] spapr/pci: Clean up local variable shadowing in spapr_phb_realize() Markus Armbruster
2023-09-29 8:50 ` [PULL 36/56] spapr/drc: Clean up local variable shadowing in prop_get_fdt() Markus Armbruster
2023-09-29 8:50 ` [PULL 37/56] test-throttle: don't shadow 'index' variable in do_test_accounting() Markus Armbruster
2023-09-29 8:50 ` [PULL 38/56] hw/acpi: changes towards enabling -Wshadow=local Markus Armbruster
2023-09-30 3:54 ` Ani Sinha
2023-09-30 8:41 ` Markus Armbruster
2023-10-02 10:49 ` Michael S. Tsirkin
2023-09-29 8:50 ` [PULL 39/56] hw/intc/arm_gicv3_its: Avoid shadowing variable in do_process_its_cmd() Markus Armbruster
2023-09-29 8:50 ` [PULL 40/56] hw/misc/arm_sysctl.c: Avoid shadowing local variable Markus Armbruster
2023-09-29 8:50 ` [PULL 41/56] hw/arm/smmuv3.c: Avoid shadowing variable Markus Armbruster
2023-09-29 8:50 ` [PULL 42/56] hw/arm/smmuv3-internal.h: Don't use locals in statement macros Markus Armbruster
2023-09-29 8:50 ` [PULL 43/56] aspeed/i2c: Clean up local variable shadowing Markus Armbruster
2023-09-29 8:50 ` [PULL 44/56] aspeed: " Markus Armbruster
2023-09-29 8:50 ` [PULL 45/56] aspeed/i3c: Rename variable shadowing a local Markus Armbruster
2023-09-29 8:50 ` [PULL 46/56] aspeed/timer: Clean up local variable shadowing Markus Armbruster
2023-09-29 8:50 ` [PULL 47/56] intel_iommu: Fix shadow local variables on "size" Markus Armbruster
2023-09-29 8:50 ` [PULL 48/56] crypto: remove shadowed 'ret' variable Markus Armbruster
2023-09-29 8:50 ` [PULL 49/56] seccomp: avoid shadowing of 'action' variable Markus Armbruster
2023-09-29 8:50 ` [PULL 50/56] qemu-nbd: changes towards enabling -Wshadow=local Markus Armbruster
2023-09-29 8:50 ` [PULL 51/56] hw/riscv: opentitan: Fixup local variables shadowing Markus Armbruster
2023-09-29 8:50 ` [PULL 52/56] target/riscv: cpu: " Markus Armbruster
2023-09-29 8:50 ` [PULL 53/56] target/riscv: vector_helper: " Markus Armbruster
2023-09-29 8:50 ` [PULL 54/56] softmmu/device_tree: " Markus Armbruster
2023-09-29 8:50 ` [PULL 55/56] hw/nvme: Clean up local variable shadowing in nvme_ns_init() Markus Armbruster
2023-09-29 8:50 ` [PULL 56/56] disas/m68k: clean up local variable shadowing Markus Armbruster
2023-10-02 21:57 ` [PULL 00/56] -Wshadow=local patches patches for 2023-09-29 Stefan Hajnoczi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230929085053.2789105-8-armbru@redhat.com \
--to=armbru@redhat.com \
--cc=eblake@redhat.com \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).