aboutsummaryrefslogtreecommitdiff
path: root/qapi
diff options
context:
space:
mode:
authorMarkus Armbruster <armbru@redhat.com>2017-03-03 13:32:45 +0100
committerMarkus Armbruster <armbru@redhat.com>2017-03-05 09:14:20 +0100
commita4a1c70dc759e5b81627e96564f344ab43ea86eb (patch)
tree56d44358c6e76c57a01aed7ee789b68965dcc2ff /qapi
parent86ca0dbe04d8eeebf460b56111c9af125e14528f (diff)
downloadqemu-a4a1c70dc759e5b81627e96564f344ab43ea86eb.zip
qemu-a4a1c70dc759e5b81627e96564f344ab43ea86eb.tar.gz
qemu-a4a1c70dc759e5b81627e96564f344ab43ea86eb.tar.bz2
qapi: Make input visitors detect unvisited list tails
Fix the design flaw demonstrated in the previous commit: new method check_list() lets input visitors report that unvisited input remains for a list, exactly like check_struct() lets them report that unvisited input remains for a struct or union. Implement the method for the qobject input visitor (straightforward), and the string input visitor (less so, due to the magic list syntax there). The opts visitor's list magic is even more impenetrable, and all I can do there today is a stub with a FIXME comment. No worse than before. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1488544368-30622-26-git-send-email-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
Diffstat (limited to 'qapi')
-rw-r--r--qapi/opts-visitor.c11
-rw-r--r--qapi/qapi-visit-core.c8
-rw-r--r--qapi/qobject-input-visitor.c37
-rw-r--r--qapi/string-input-visitor.c30
-rw-r--r--qapi/trace-events1
5 files changed, 81 insertions, 6 deletions
diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index c50dc4b..026d25b 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -273,6 +273,16 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size)
static void
+opts_check_list(Visitor *v, Error **errp)
+{
+ /*
+ * FIXME should set error when unvisited elements remain. Mostly
+ * harmless, as the generated visits always visit all elements.
+ */
+}
+
+
+static void
opts_end_list(Visitor *v, void **obj)
{
OptsVisitor *ov = to_ov(v);
@@ -539,6 +549,7 @@ opts_visitor_new(const QemuOpts *opts)
ov->visitor.start_list = &opts_start_list;
ov->visitor.next_list = &opts_next_list;
+ ov->visitor.check_list = &opts_check_list;
ov->visitor.end_list = &opts_end_list;
ov->visitor.type_int64 = &opts_type_int64;
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index e6e93f0..43a09d1 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -90,6 +90,14 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size)
return v->next_list(v, tail, size);
}
+void visit_check_list(Visitor *v, Error **errp)
+{
+ trace_visit_check_list(v);
+ if (v->check_list) {
+ v->check_list(v, errp);
+ }
+}
+
void visit_end_list(Visitor *v, void **obj)
{
trace_visit_end_list(v, obj);
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index eafcdf4..34065ba 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -51,7 +51,8 @@ static QObjectInputVisitor *to_qiv(Visitor *v)
return container_of(v, QObjectInputVisitor, visitor);
}
-static const char *full_name(QObjectInputVisitor *qiv, const char *name)
+static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name,
+ int n)
{
StackObject *so;
char buf[32];
@@ -63,8 +64,10 @@ static const char *full_name(QObjectInputVisitor *qiv, const char *name)
}
QSLIST_FOREACH(so , &qiv->stack, node) {
- if (qobject_type(so->obj) == QTYPE_QDICT) {
- g_string_prepend(qiv->errname, name);
+ if (n) {
+ n--;
+ } else if (qobject_type(so->obj) == QTYPE_QDICT) {
+ g_string_prepend(qiv->errname, name ?: "<anonymous>");
g_string_prepend_c(qiv->errname, '.');
} else {
snprintf(buf, sizeof(buf), "[%u]", so->index);
@@ -72,18 +75,24 @@ static const char *full_name(QObjectInputVisitor *qiv, const char *name)
}
name = so->name;
}
+ assert(!n);
if (name) {
g_string_prepend(qiv->errname, name);
} else if (qiv->errname->str[0] == '.') {
g_string_erase(qiv->errname, 0, 1);
- } else {
+ } else if (!qiv->errname->str[0]) {
return "<anonymous>";
}
return qiv->errname->str;
}
+static const char *full_name(QObjectInputVisitor *qiv, const char *name)
+{
+ return full_name_nth(qiv, name, 0);
+}
+
static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv,
const char *name,
bool consume)
@@ -260,15 +269,30 @@ static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
size_t size)
{
QObjectInputVisitor *qiv = to_qiv(v);
- StackObject *so = QSLIST_FIRST(&qiv->stack);
+ StackObject *tos = QSLIST_FIRST(&qiv->stack);
+
+ assert(tos && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST);
- if (!so->entry) {
+ if (!tos->entry) {
return NULL;
}
tail->next = g_malloc0(size);
return tail->next;
}
+static void qobject_input_check_list(Visitor *v, Error **errp)
+{
+ QObjectInputVisitor *qiv = to_qiv(v);
+ StackObject *tos = QSLIST_FIRST(&qiv->stack);
+
+ assert(tos && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST);
+
+ if (tos->entry) {
+ error_setg(errp, "Only %u list elements expected in %s",
+ tos->index + 1, full_name_nth(qiv, NULL, 1));
+ }
+}
+
static void qobject_input_start_alternate(Visitor *v, const char *name,
GenericAlternate **obj, size_t size,
@@ -471,6 +495,7 @@ Visitor *qobject_input_visitor_new(QObject *obj)
v->visitor.end_struct = qobject_input_pop;
v->visitor.start_list = qobject_input_start_list;
v->visitor.next_list = qobject_input_next_list;
+ v->visitor.check_list = qobject_input_check_list;
v->visitor.end_list = qobject_input_pop;
v->visitor.start_alternate = qobject_input_start_alternate;
v->visitor.type_int64 = qobject_input_type_int64;
diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
index f126cd9..806b01ae 100644
--- a/qapi/string-input-visitor.c
+++ b/qapi/string-input-visitor.c
@@ -170,6 +170,35 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
return tail->next;
}
+static void check_list(Visitor *v, Error **errp)
+{
+ const StringInputVisitor *siv = to_siv(v);
+ Range *r;
+ GList *cur_range;
+
+ if (!siv->ranges || !siv->cur_range) {
+ return;
+ }
+
+ r = siv->cur_range->data;
+ if (!r) {
+ return;
+ }
+
+ if (!range_contains(r, siv->cur)) {
+ cur_range = g_list_next(siv->cur_range);
+ if (!cur_range) {
+ return;
+ }
+ r = cur_range->data;
+ if (!r) {
+ return;
+ }
+ }
+
+ error_setg(errp, "Range contains too many values");
+}
+
static void end_list(Visitor *v, void **obj)
{
StringInputVisitor *siv = to_siv(v);
@@ -318,6 +347,7 @@ Visitor *string_input_visitor_new(const char *str)
v->visitor.type_number = parse_type_number;
v->visitor.start_list = start_list;
v->visitor.next_list = next_list;
+ v->visitor.check_list = check_list;
v->visitor.end_list = end_list;
v->visitor.free = string_input_free;
diff --git a/qapi/trace-events b/qapi/trace-events
index 9cbb61b..339cacf 100644
--- a/qapi/trace-events
+++ b/qapi/trace-events
@@ -8,6 +8,7 @@ visit_end_struct(void *v, void *obj) "v=%p obj=%p"
visit_start_list(void *v, const char *name, void *obj, size_t size) "v=%p name=%s obj=%p size=%zu"
visit_next_list(void *v, void *tail, size_t size) "v=%p tail=%p size=%zu"
+visit_check_list(void *v) "v=%p"
visit_end_list(void *v, void *obj) "v=%p obj=%p"
visit_start_alternate(void *v, const char *name, void *obj, size_t size, bool promote_int) "v=%p name=%s obj=%p size=%zu promote_int=%d"