]> xenbits.xensource.com Git - libvirt.git/commitdiff
object: Add sanity check on correct parent class
authorEric Blake <eblake@redhat.com>
Fri, 15 Mar 2019 14:41:18 +0000 (09:41 -0500)
committerEric Blake <eblake@redhat.com>
Fri, 15 Mar 2019 16:10:12 +0000 (11:10 -0500)
Checking that the derived class is larger than the requested parent
class saves us from some obvious mistakes, but as written, it does not
catch all the cases; in particular, it is easy to forget to update a
VIR_CLASS_NEW when changing the 'parent' member from virObject to
virObjectLockabale, but where the size checks don't catch that.  Add a
parameter for one more layer of sanity checking.

It would be cool if we could get gcc to stringize typeof(parent) into
the string name of that type, so that we could confirm that the
precise parent class is in use rather than just a struct that happens
to have the same size as the parent class.  But sizeof checks are
better than nothing.

Note that I did NOT change the fact that we require derived classes to
be larger (as the difference in size makes it easy to tell classes
apart), which means that even if a derived class has no functionality
to add (but rather exists for compiler-enforced type-safety), it must
still include a dummy member.  But I did fix the wording of the error
message to match the code.

Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
src/util/virobject.c
src/util/virobject.h

index 3b28331ba780f25096f70c054a30afcc2f919467..919519735a694d87c7491676208fd75e4a93d589 100644 (file)
@@ -78,6 +78,7 @@ virObjectOnceInit(void)
     if (!(virObjectClass = virClassNew(NULL,
                                        "virObject",
                                        sizeof(virObject),
+                                       0,
                                        NULL)))
         return -1;
 
@@ -159,6 +160,7 @@ virClassPtr
 virClassNew(virClassPtr parent,
             const char *name,
             size_t objectSize,
+            size_t parentSize,
             virObjectDisposeCallback dispose)
 {
     virClassPtr klass;
@@ -167,10 +169,11 @@ virClassNew(virClassPtr parent,
         STRNEQ(name, "virObject")) {
         virReportInvalidNonNullArg(parent);
         return NULL;
-    } else if (parent &&
-               objectSize <= parent->objectSize) {
+    } else if (objectSize <= parentSize ||
+               parentSize != (parent ? parent->objectSize : 0)) {
+        sa_assert(parent);
         virReportInvalidArg(objectSize,
-                            _("object size %zu of %s is smaller than parent class %zu"),
+                            _("object size %zu of %s is not larger than parent class %zu"),
                             objectSize, name, parent->objectSize);
         return NULL;
     }
index d4ec943a43d4f8033c95bce9483211281adc8808..757068fcc149ecba19657e427cbecc2e6900c1b2 100644 (file)
@@ -82,12 +82,15 @@ virClassPtr virClassForObjectRWLockable(void);
  */
 # define VIR_CLASS_NEW(name, prnt) \
     verify_expr(offsetof(name, parent) == 0, \
-      (name##Class = virClassNew(prnt, #name, sizeof(name), name##Dispose)))
+      (name##Class = virClassNew(prnt, #name, sizeof(name), \
+                                 sizeof(((name *)NULL)->parent), \
+                                 name##Dispose)))
 
 virClassPtr
 virClassNew(virClassPtr parent,
             const char *name,
             size_t objectSize,
+            size_t parentSize,
             virObjectDisposeCallback dispose)
     VIR_PARENT_REQUIRED ATTRIBUTE_NONNULL(2);