From: Markus Armbruster <armbru@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, hreitz@redhat.com, eblake@redhat.com,
vsementsov@yandex-team.ru, jsnow@redhat.com, idryomov@gmail.com,
pl@kamp.de, sw@weilnetz.de, sstabellini@kernel.org,
anthony.perard@citrix.com, paul@xen.org, pbonzini@redhat.com,
marcandre.lureau@redhat.com, berrange@redhat.com,
thuth@redhat.com, philmd@linaro.org, stefanha@redhat.com,
fam@euphon.net, quintela@redhat.com, peterx@redhat.com,
leobras@redhat.com, kraxel@redhat.com, qemu-block@nongnu.org,
xen-devel@lists.xenproject.org, alex.bennee@linaro.org,
peter.maydell@linaro.org
Subject: [PATCH 7/7] qobject atomics osdep: Make a few macros more hygienic
Date: Thu, 31 Aug 2023 15:25:46 +0200 [thread overview]
Message-ID: <20230831132546.3525721-8-armbru@redhat.com> (raw)
In-Reply-To: <20230831132546.3525721-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>
---
include/qapi/qmp/qobject.h | 8 +++++---
include/qemu/atomic.h | 11 ++++++-----
include/qemu/osdep.h | 34 +++++++++++++++++++---------------
3 files changed, 30 insertions(+), 23 deletions(-)
diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h
index 9003b71fd3..7b50fc905d 100644
--- a/include/qapi/qmp/qobject.h
+++ b/include/qapi/qmp/qobject.h
@@ -45,10 +45,12 @@ struct QObject {
struct QObjectBase_ base;
};
-#define QOBJECT(obj) ({ \
- typeof(obj) _obj = (obj); \
- _obj ? container_of(&(_obj)->base, QObject, base) : NULL; \
+#define QOBJECT_INTERNAL(obj, l) ({ \
+ typeof(obj) PASTE(_obj, l) = (obj); \
+ PASTE(_obj, l) \
+ ? container_of(&(PASTE(_obj, l))->base, QObject, base) : NULL; \
})
+#define QOBJECT(obj) QOBJECT_INTERNAL((obj), __COUNTER__)
/* 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..3f80ffac69 100644
--- a/include/qemu/atomic.h
+++ b/include/qemu/atomic.h
@@ -157,13 +157,14 @@
smp_read_barrier_depends();
#endif
-#define qatomic_rcu_read(ptr) \
- ({ \
+#define qatomic_rcu_read_internal(ptr, l) \
+ ({ \
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
- typeof_strip_qual(*ptr) _val; \
- qatomic_rcu_read__nocheck(ptr, &_val); \
- _val; \
+ typeof_strip_qual(*ptr) PASTE(_val, l); \
+ qatomic_rcu_read__nocheck(ptr, &PASTE(_val, l)); \
+ PASTE(_val, l); \
})
+#define qatomic_rcu_read(ptr) qatomic_rcu_read_internal((ptr), __COUNTER__)
#define qatomic_rcu_set(ptr, i) do { \
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 21ef8f1699..9c191ebe99 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -371,18 +371,21 @@ void QEMU_ERROR("code path is reachable")
* have to open-code it. Sadly, Coverity is severely confused by the
* constant variants, so we have to dumb things down there.
*/
+#define PASTE(a, b) a##b
+#define MIN_INTERNAL(a, b, l) \
+ ({ \
+ typeof(1 ? (a) : (b)) PASTE(_a, l) = (a), PASTE(_b, l) = (b); \
+ PASTE(_a, l) < PASTE(_b, l) ? PASTE(_a, l) : PASTE(_b, l); \
+ })
#undef MIN
-#define MIN(a, b) \
- ({ \
- typeof(1 ? (a) : (b)) _a = (a), _b = (b); \
- _a < _b ? _a : _b; \
+#define MIN(a, b) MIN_INTERNAL((a), (b), __COUNTER__)
+#define MAX_INTERNAL(a, b, l) \
+ ({ \
+ typeof(1 ? (a) : (b)) PASTE(_a, l) = (a), PASTE(_b, l) = (b); \
+ PASTE(_a, l) > PASTE(_b, l) ? PASTE(_a, l) : PASTE(_b, l); \
})
#undef MAX
-#define MAX(a, b) \
- ({ \
- typeof(1 ? (a) : (b)) _a = (a), _b = (b); \
- _a > _b ? _a : _b; \
- })
+#define MAX(a, b) MAX_INTERNAL((a), (b), __COUNTER__)
#ifdef __COVERITY__
# define MIN_CONST(a, b) ((a) < (b) ? (a) : (b))
@@ -404,13 +407,14 @@ 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.
*/
-#ifndef MIN_NON_ZERO
-#define MIN_NON_ZERO(a, b) \
- ({ \
- typeof(1 ? (a) : (b)) _a = (a), _b = (b); \
- _a == 0 ? _b : (_b == 0 || _b > _a) ? _a : _b; \
+#define MIN_NON_ZERO_INTERNAL(a, b, l) \
+ ({ \
+ typeof(1 ? (a) : (b)) PASTE(_a, l) = (a), PASTE(_b, l) = (b); \
+ PASTE(_a, l) == 0 ? PASTE(_b, l) \
+ : (PASTE(_b, l) == 0 || PASTE(_b, l) > PASTE(_a, l)) ? PASTE(_a, l) \
+ : PASTE(_b, l); \
})
-#endif
+#define MIN_NON_ZERO(a, b) MIN_NON_ZERO_INTERNAL((a), (b), __COUNTER__)
/*
* 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-08-31 13:27 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-31 13:25 [PATCH 0/7] Steps towards enabling -Wshadow=local Markus Armbruster
2023-08-31 13:25 ` [PATCH 1/7] migration/rdma: Fix save_page method to fail on polling error Markus Armbruster
2023-08-31 13:38 ` Eric Blake
2023-09-19 5:40 ` Markus Armbruster
2023-08-31 20:17 ` Peter Xu
2023-09-06 3:48 ` Zhijian Li (Fujitsu)
2023-08-31 13:25 ` [PATCH 2/7] migration: Clean up local variable shadowing Markus Armbruster
2023-08-31 20:19 ` Peter Xu
2023-08-31 13:25 ` [PATCH 3/7] ui: " Markus Armbruster
2023-08-31 14:53 ` Peter Maydell
2023-09-01 8:11 ` Markus Armbruster
2023-08-31 13:25 ` [PATCH 4/7] block/dirty-bitmap: " Markus Armbruster
2023-08-31 19:29 ` Stefan Hajnoczi
2023-09-15 7:52 ` Kevin Wolf
2023-09-19 5:48 ` Markus Armbruster
2023-09-19 9:45 ` Kevin Wolf
2023-09-20 13:38 ` Markus Armbruster
2023-08-31 13:25 ` [PATCH 5/7] block/vdi: " Markus Armbruster
2023-08-31 19:26 ` Stefan Hajnoczi
2023-09-15 7:41 ` Kevin Wolf
2023-09-18 14:47 ` Markus Armbruster
2023-08-31 13:25 ` [PATCH 6/7] block: " Markus Armbruster
2023-08-31 19:24 ` Stefan Hajnoczi
2023-09-11 10:44 ` Anthony PERARD
2023-09-11 11:17 ` Ilya Dryomov
2023-09-15 8:10 ` Kevin Wolf
2023-09-18 14:49 ` Markus Armbruster
2023-08-31 13:25 ` Markus Armbruster [this message]
2023-08-31 14:30 ` [PATCH 7/7] qobject atomics osdep: Make a few macros more hygienic Eric Blake
2023-09-01 8:48 ` Markus Armbruster
2023-09-01 13:18 ` Eric Blake
2023-09-19 6:29 ` Markus Armbruster
2023-09-01 12:59 ` Cédric Le Goater
2023-09-01 14:31 ` Philippe Mathieu-Daudé
2023-09-01 14:50 ` Markus Armbruster
2023-09-01 14:54 ` Cédric Le Goater
2023-08-31 15:52 ` Richard Henderson
2023-09-01 8:12 ` Markus Armbruster
2023-09-01 8:05 ` [PATCH 0/7] Steps towards enabling -Wshadow=local Markus Armbruster
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=20230831132546.3525721-8-armbru@redhat.com \
--to=armbru@redhat.com \
--cc=alex.bennee@linaro.org \
--cc=anthony.perard@citrix.com \
--cc=berrange@redhat.com \
--cc=eblake@redhat.com \
--cc=fam@euphon.net \
--cc=hreitz@redhat.com \
--cc=idryomov@gmail.com \
--cc=jsnow@redhat.com \
--cc=kraxel@redhat.com \
--cc=kwolf@redhat.com \
--cc=leobras@redhat.com \
--cc=marcandre.lureau@redhat.com \
--cc=paul@xen.org \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=peterx@redhat.com \
--cc=philmd@linaro.org \
--cc=pl@kamp.de \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=quintela@redhat.com \
--cc=sstabellini@kernel.org \
--cc=stefanha@redhat.com \
--cc=sw@weilnetz.de \
--cc=thuth@redhat.com \
--cc=vsementsov@yandex-team.ru \
--cc=xen-devel@lists.xenproject.org \
/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).