qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC/RFA PATCH] qapi: detect extra members inside structs


From: Paolo Bonzini
Subject: [Qemu-devel] [RFC/RFA PATCH] qapi: detect extra members inside structs
Date: Mon, 19 Mar 2012 20:29:28 +0100

I noticed that the QMP input visitor does not detect extra members inside
structs.  The outermost arguments struct is handled by the QMP type
checker, but the nested ones go undetected.  That could be a problem
for complex commands such as "transaction".

This patch adds such detection to the QMP input visitor.

Signed-off-by: Paolo Bonzini <address@hidden>
---
        Is this acceptable or just wrong?

        Other small problems I noticed in running the testsuite:
        why is qemu-ga$(EXESUF) in tests/Makefile and test-qmp-commands
        not run by "make check"?

 qapi/qmp-input-visitor.c |   19 ++++++++++++++++--
 qerror.h                 |    3 +++
 test-qmp-input-visitor.c |   19 +++++++++++++++++++
 3 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index e6b6152..416ab90 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -23,7 +23,8 @@
 typedef struct StackObject
 {
     const QObject *obj;
-    const  QListEntry *entry;
+    const QListEntry *entry;
+    int   left;
 } StackObject;
 
 struct QmpInputVisitor
@@ -31,6 +32,7 @@ struct QmpInputVisitor
     Visitor visitor;
     QObject *obj;
     StackObject stack[QIV_STACK_SIZE];
+    int left;
     int nb_stack;
 };
 
@@ -52,8 +54,13 @@ static const QObject *qmp_input_get_object(QmpInputVisitor 
*qiv,
 
     if (qobj) {
         if (name && qobject_type(qobj) == QTYPE_QDICT) {
-            return qdict_get(qobject_to_qdict(qobj), name);
+            qobj = qdict_get(qobject_to_qdict(qobj), name);
+            if (qobj) {
+                assert(qiv->left > 0);
+                qiv->left--;
+            }
         } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
+            assert(qiv->left == -1);
             return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
         }
     }
@@ -64,10 +70,12 @@ static const QObject *qmp_input_get_object(QmpInputVisitor 
*qiv,
 static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error 
**errp)
 {
     qiv->stack[qiv->nb_stack].obj = obj;
+    qiv->stack[qiv->nb_stack].left = qiv->left;
     if (qobject_type(obj) == QTYPE_QLIST) {
         qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
     }
     qiv->nb_stack++;
+    qiv->left = -1;
 
     if (qiv->nb_stack >= QIV_STACK_SIZE) {
         error_set(errp, QERR_BUFFER_OVERRUN);
@@ -77,7 +85,12 @@ static void qmp_input_push(QmpInputVisitor *qiv, const 
QObject *obj, Error **err
 
 static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
 {
+    if (qiv->left != -1 && qiv->left != 0) {
+        error_set(errp, QERR_EXTRA_MEMBER);
+        return;
+    }
     qiv->nb_stack--;
+    qiv->left = qiv->stack[qiv->nb_stack].left;
     if (qiv->nb_stack < 0) {
         error_set(errp, QERR_BUFFER_OVERRUN);
         return;
@@ -97,6 +110,7 @@ static void qmp_input_start_struct(Visitor *v, void **obj, 
const char *kind,
     }
 
     qmp_input_push(qiv, qobj, errp);
+    qiv->left = qdict_size(qobject_to_qdict(qobj));
     if (error_is_set(errp)) {
         return;
     }
diff --git a/qerror.h b/qerror.h
index e26c635..520cdab 100644
--- a/qerror.h
+++ b/qerror.h
@@ -127,6 +127,9 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_DUPLICATE_ID \
     "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
 
+#define QERR_EXTRA_MEMBER \
+    "{ 'class': 'ExtraInputObjectMember', 'data': {} }"
+
 #define QERR_FD_NOT_FOUND \
     "{ 'class': 'FdNotFound', 'data': { 'name': %s } }"
 
diff --git a/test-qmp-input-visitor.c b/test-qmp-input-visitor.c
index 1996e49..1783759 100644
--- a/test-qmp-input-visitor.c
+++ b/test-qmp-input-visitor.c
@@ -161,6 +161,23 @@ static void visit_type_TestStruct(Visitor *v, TestStruct 
**obj,
     visit_end_struct(v, errp);
 }
 
+static void test_visitor_in_struct_extra(TestInputVisitorData *data,
+                                         const void *unused)
+{
+    TestStruct *p = NULL;
+    Error *errp = NULL;
+    Visitor *v;
+
+    v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 
'string': 'foo', 'extra' : [ 123, 456, 'def' ] }");
+
+    visit_type_TestStruct(v, &p, NULL, &errp);
+    g_assert(error_is_set(&errp));
+    if (p) {
+        g_free(p->string);
+        g_free(p);
+    }
+}
+
 static void test_visitor_in_struct(TestInputVisitorData *data,
                                    const void *unused)
 {
@@ -278,6 +295,8 @@ int main(int argc, char **argv)
                             &in_visitor_data, test_visitor_in_struct);
     input_visitor_test_add("/visitor/input/struct-nested",
                             &in_visitor_data, test_visitor_in_struct_nested);
+    input_visitor_test_add("/visitor/input/struct-extra",
+                            &in_visitor_data, test_visitor_in_struct_extra);
     input_visitor_test_add("/visitor/input/list",
                             &in_visitor_data, test_visitor_in_list);
     input_visitor_test_add("/visitor/input/union",
-- 
1.7.7.6




reply via email to

[Prev in Thread] Current Thread [Next in Thread]