Simplify casting to QObject by not requiring the definition of the type and assuming base QObject is at offset 0. Add a static check for this.
Use the QEMU_GENERIC macro for keeping type safety check and error when given an unknown type. Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com> --- include/qapi/qmp/qobject.h | 36 ++++++++++++++++++++++++++++++++++-- qobject/qobject.c | 9 +++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index e022707578..d0aead35ec 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -39,8 +39,40 @@ struct QObject { size_t refcnt; }; -/* Get the 'base' part of an object */ -#define QOBJECT(obj) (&(obj)->base) +/* This function gives an error if an invalid pointer type is passed + * to QOBJECT. For optimized builds, we can rely on dead-code + * elimination from the compiler, and give the errors already at link + * time. + */ +#if defined(__OPTIMIZE__) && !defined(__SANITIZE_ADDRESS__) +const void * qobject_unknown_type(const void *); +#else +static inline const void * +qobject_unknown_type(const void *unused) +{ + abort(); + return NULL; +} +#endif + +/* A typecast, checking for the type of arguments */ +/* QObject is at offset 0, for all QObject-derived types */ +#define QOBJECT(x) QEMU_GENERIC(x, \ + (QNull *, (QObject *) x), \ + (const QNull *, (const QObject *) x), \ + (QNum *, (QObject *) x), \ + (const QNum *, (const QObject *) x), \ + (QString *, (QObject *) x), \ + (const QString *, (const QObject *) x), \ + (QDict *, (QObject *) x), \ + (const QDict *, (const QObject *) x), \ + (QList *, (QObject *) x), \ + (const QList *, (const QObject *) x), \ + (QBool *, (QObject *) x), \ + (const QBool *, (const QObject *) x), \ + (QObject *, x), \ + (const QObject *, x), \ + qobject_unknown_type(x)) /* High-level interface for qobject_incref() */ #define QINCREF(obj) \ diff --git a/qobject/qobject.c b/qobject/qobject.c index 23600aa1c1..87649c5be5 100644 --- a/qobject/qobject.c +++ b/qobject/qobject.c @@ -16,6 +16,15 @@ #include "qapi/qmp/qlist.h" #include "qapi/qmp/qstring.h" +QEMU_BUILD_BUG_MSG( + offsetof(QNull, base) != 0 || + offsetof(QNum, base) != 0 || + offsetof(QString, base) != 0 || + offsetof(QDict, base) != 0 || + offsetof(QList, base) != 0 || + offsetof(QBool, base) != 0, + "base qobject must be at offset 0"); + static void (*qdestroy[QTYPE__MAX])(QObject *) = { [QTYPE_NONE] = NULL, /* No such object exists */ [QTYPE_QNULL] = NULL, /* qnull_ is indestructible */ -- 2.16.2.521.g9aa15f885a