All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Eric Blake <eblake@redhat.com>
Cc: qemu-devel@nongnu.org, Michael Roth <mdroth@linux.vnet.ibm.com>
Subject: Re: [Qemu-devel] [PATCH v14 13/19] qmp: Tighten output visitor rules
Date: Fri, 15 Apr 2016 11:02:31 +0200	[thread overview]
Message-ID: <877ffzutw8.fsf@dusky.pond.sub.org> (raw)
In-Reply-To: <1460131992-32278-14-git-send-email-eblake@redhat.com> (Eric Blake's message of "Fri, 8 Apr 2016 10:13:06 -0600")

Eric Blake <eblake@redhat.com> writes:

> Add a new qmp_output_visitor_reset(), which must be called before
> reusing an exising QmpOutputVisitor on a new root object.  Tighten
> assertions to require that qmp_output_get_qobject() can only be
> called after pairing a visit_end_* for every visit_start_* (rather
> than allowing it to return a partially built object), and that it
> must not be called unless at least one visit_type_* or visit_start/
> visit_end pair has occurred since creation/reset (the accidental
> return of NULL fixed by commit ab8bf1d7 would have been much
> easier to diagnose).
>
> Also, check that we are encountering the expected object or list
> type (both during visit_end*, and also by validating whether 'name'
> was NULL - although the latter may need to change later if we
> improve error messages by always passing in a sensible name).
> This provides protection against mismatched push(struct)/pop(list)
> or push(list)/pop(struct), similar to the qmp-input protection
> added in commit bdd8e6b5.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>

As written, the commit message makes me wonder why we add
qmp_output_visitor_reset() in the same commit.  I think the reason is
the tightened rules make it necessary.  The commit message could make
that clearer by explaining the rule changes first, then point out we
need a reset to comply with the rules.

>
> ---
> v14: no change
> v13: no change
> v12: rebase to latest, move type_null() into earlier patches,
> don't change signature of pop, don't auto-reset after a single
> get_qobject
> [no v10, v11]
> v9: rebase to added patch, squash in more sanity checks, drop
> Marc-Andre's R-b
> v8: rename qmp_output_reset to qmp_output_visitor_reset
> v7: new patch, based on discussion about spapr_drc.c
> ---
>  include/qapi/qmp-output-visitor.h |  1 +
>  qapi/qmp-output-visitor.c         | 39 +++++++++++++++++++++++----------------
>  tests/test-qmp-output-visitor.c   |  6 ++++++
>  3 files changed, 30 insertions(+), 16 deletions(-)
>
> diff --git a/include/qapi/qmp-output-visitor.h b/include/qapi/qmp-output-visitor.h
> index 2266770..5093f0d 100644
> --- a/include/qapi/qmp-output-visitor.h
> +++ b/include/qapi/qmp-output-visitor.h
> @@ -21,6 +21,7 @@ typedef struct QmpOutputVisitor QmpOutputVisitor;
>
>  QmpOutputVisitor *qmp_output_visitor_new(void);
>  void qmp_output_visitor_cleanup(QmpOutputVisitor *v);
> +void qmp_output_visitor_reset(QmpOutputVisitor *v);
>
>  QObject *qmp_output_get_qobject(QmpOutputVisitor *v);
>  Visitor *qmp_output_get_visitor(QmpOutputVisitor *v);
> diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
> index 5681ad3..7c48dfb 100644
> --- a/qapi/qmp-output-visitor.c
> +++ b/qapi/qmp-output-visitor.c
> @@ -82,9 +82,8 @@ static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
>      QObject *cur = e ? e->value : NULL;
>
>      if (!cur) {
> -        /* FIXME we should require the user to reset the visitor, rather
> -         * than throwing away the previous root */
> -        qobject_decref(qov->root);
> +        /* Don't allow reuse of visitor on more than one root */
> +        assert(!qov->root);
>          qov->root = value;
>      } else {
>          switch (qobject_type(cur)) {
> @@ -93,6 +92,9 @@ static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
>              qdict_put_obj(qobject_to_qdict(cur), name, value);
>              break;
>          case QTYPE_QLIST:
> +            /* FIXME: assertion needs adjustment if we fix visit-core
> +             * to pass "name.0" style name during lists.  */

visit-core merely passes through whatever name it gets from the client.
Thus, saying we 'fix visit-core to pass "name.0"' is a bit misleading.
What we'd do is change it to require "name.0", then update its users to
comply.

Moreover, this is a note, not a FIXME: nothing is broken here.  The
closest we get to "broken" are the bad error messages, but they're
elsewhere.

I'd simply drop the comment.

> +            assert(!name);

PATCH 08 made this part of the contract.  It also added a bunch of
contract-checking assertions.  Should this one be in PATCH 08, too?

>              qlist_append_obj(qobject_to_qlist(cur), value);
>              break;
>          default:
> @@ -114,7 +116,8 @@ static void qmp_output_start_struct(Visitor *v, const char *name, void **obj,
>  static void qmp_output_end_struct(Visitor *v, Error **errp)
>  {
>      QmpOutputVisitor *qov = to_qov(v);
> -    qmp_output_pop(qov);
> +    QObject *value = qmp_output_pop(qov);
> +    assert(qobject_type(value) == QTYPE_QDICT);
>  }
>
>  static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
> @@ -145,7 +148,8 @@ static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
>  static void qmp_output_end_list(Visitor *v)
>  {
>      QmpOutputVisitor *qov = to_qov(v);
> -    qmp_output_pop(qov);
> +    QObject *value = qmp_output_pop(qov);
> +    assert(qobject_type(value) == QTYPE_QLIST);
>  }
>
>  static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj,
> @@ -202,18 +206,15 @@ static void qmp_output_type_null(Visitor *v, const char *name, Error **errp)
>      qmp_output_add_obj(qov, name, qnull());
>  }
>
> -/* Finish building, and return the root object. Will not be NULL. */
> +/* Finish building, and return the root object. Will not be NULL.
> + * Caller must use qobject_decref() on the result.  */

Well, it must only if it wants the object freed, but I know what you
mean.

Perhaps:

   /*
    * Finish building, and return the root object.
    * The root object is never null.
    * The caller becomes the object's owner.  It should free it with
    * qobject_decref().
    */
  
>  QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
>  {
> -    /* FIXME: we should require that a visit occurred, and that it is
> -     * complete (no starts without a matching end) */
> -    QObject *obj = qov->root;
> -    if (obj) {
> -        qobject_incref(obj);
> -    } else {
> -        obj = qnull();
> -    }
> -    return obj;
> +    /* A visit must have occurred, with each start paired with end.  */
> +    assert(qov->root && !QTAILQ_FIRST(&qov->stack));

&& QTAILQ_EMPTY(&qov-stack) would be clearer, wouldn't it?

> +
> +    qobject_incref(qov->root);
> +    return qov->root;
>  }
>
>  Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
> @@ -221,7 +222,7 @@ Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
>      return &v->visitor;
>  }
>
> -void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
> +void qmp_output_visitor_reset(QmpOutputVisitor *v)
>  {
>      QStackEntry *e, *tmp;
>
> @@ -231,6 +232,12 @@ void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
>      }
>
>      qobject_decref(v->root);
> +    v->root = NULL;
> +}
> +
> +void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
> +{
> +    qmp_output_visitor_reset(v);
>      g_free(v);
>  }
>
> diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
> index e656d99..7be33ba 100644
> --- a/tests/test-qmp-output-visitor.c
> +++ b/tests/test-qmp-output-visitor.c
> @@ -139,6 +139,7 @@ static void test_visitor_out_enum(TestOutputVisitorData *data,
>          g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==,
>                          EnumOne_lookup[i]);
>          qobject_decref(obj);
> +        qmp_output_visitor_reset(data->qov);
>      }
>  }
>
> @@ -153,6 +154,7 @@ static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
>          visit_type_EnumOne(data->ov, "unused", &bad_values[i], &err);
>          g_assert(err);
>          error_free(err);
> +        qmp_output_visitor_reset(data->qov);
>      }
>  }
>
> @@ -262,6 +264,7 @@ static void test_visitor_out_struct_errors(TestOutputVisitorData *data,
>          visit_type_UserDefOne(data->ov, "unused", &pu, &err);
>          g_assert(err);
>          error_free(err);
> +        qmp_output_visitor_reset(data->qov);
>      }
>  }
>
> @@ -366,6 +369,7 @@ static void test_visitor_out_any(TestOutputVisitorData *data,
>      qobject_decref(obj);
>      qobject_decref(qobj);
>
> +    qmp_output_visitor_reset(data->qov);
>      qdict = qdict_new();
>      qdict_put(qdict, "integer", qint_from_int(-42));
>      qdict_put(qdict, "boolean", qbool_from_bool(true));
> @@ -442,6 +446,7 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
>      qapi_free_UserDefAlternate(tmp);
>      qobject_decref(arg);
>
> +    qmp_output_visitor_reset(data->qov);
>      tmp = g_new0(UserDefAlternate, 1);
>      tmp->type = QTYPE_QSTRING;
>      tmp->u.s = g_strdup("hello");
> @@ -455,6 +460,7 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
>      qapi_free_UserDefAlternate(tmp);
>      qobject_decref(arg);
>
> +    qmp_output_visitor_reset(data->qov);
>      tmp = g_new0(UserDefAlternate, 1);
>      tmp->type = QTYPE_QDICT;
>      tmp->u.udfu.integer = 1;

How did you find the places that now need qmp_output_visitor_reset()?

  reply	other threads:[~2016-04-15  9:02 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-08 16:12 [Qemu-devel] [PATCH v14 00/19] qapi visitor cleanups (post-introspection cleanups subset E) Eric Blake
2016-04-08 16:12 ` [Qemu-devel] [PATCH v14 01/19] qapi: Consolidate object visitors Eric Blake
2016-04-13 12:48   ` Markus Armbruster
2016-04-13 16:13     ` Eric Blake
2016-04-15 15:05       ` Markus Armbruster
2016-04-08 16:12 ` [Qemu-devel] [PATCH v14 02/19] qapi-visit: Add visitor.type classification Eric Blake
2016-04-13 13:49   ` Markus Armbruster
2016-04-13 16:23     ` Eric Blake
2016-04-15 15:24       ` Markus Armbruster
2016-04-08 16:12 ` [Qemu-devel] [PATCH v14 03/19] qapi: Guarantee NULL obj on input visitor callback error Eric Blake
2016-04-13 14:04   ` Markus Armbruster
2016-04-08 16:12 ` [Qemu-devel] [PATCH v14 04/19] qmp: Drop dead command->type Eric Blake
2016-04-08 16:12 ` [Qemu-devel] [PATCH v14 05/19] qmp-input: Clean up stack handling Eric Blake
2016-04-13 15:53   ` Markus Armbruster
2016-04-13 16:36     ` Eric Blake
2016-04-13 16:40       ` Eric Blake
2016-04-15 15:27       ` Markus Armbruster
2016-04-08 16:12 ` [Qemu-devel] [PATCH v14 06/19] qmp-input: Don't consume input when checking has_member Eric Blake
2016-04-13 16:06   ` Markus Armbruster
2016-04-13 16:43     ` Eric Blake
2016-04-15 15:28       ` Markus Armbruster
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 07/19] qmp-input: Refactor when list is advanced Eric Blake
2016-04-13 17:38   ` Markus Armbruster
2016-04-13 19:58     ` Eric Blake
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 08/19] qapi: Document visitor interfaces, add assertions Eric Blake
2016-04-14 15:22   ` Markus Armbruster
2016-04-26 21:50     ` Eric Blake
2016-04-28 16:33       ` Markus Armbruster
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 09/19] tests: Add check-qnull Eric Blake
2016-04-14 16:13   ` Markus Armbruster
2016-04-14 17:37     ` Markus Armbruster
2016-04-14 18:54       ` Eric Blake
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 10/19] qapi: Add visit_type_null() visitor Eric Blake
2016-04-14 17:09   ` Markus Armbruster
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 11/19] qmp: Support explicit null during visits Eric Blake
2016-04-15  8:29   ` Markus Armbruster
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 12/19] spapr_drc: Expose 'null' in qom-get when there is no fdt Eric Blake
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 13/19] qmp: Tighten output visitor rules Eric Blake
2016-04-15  9:02   ` Markus Armbruster [this message]
2016-04-27  1:29     ` Eric Blake
2016-04-27  6:29       ` Markus Armbruster
2016-04-27 12:22         ` Eric Blake
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 14/19] qapi: Split visit_end_struct() into pieces Eric Blake
2016-04-15 11:03   ` Markus Armbruster
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 15/19] qapi-commands: Wrap argument visit in visit_start_struct Eric Blake
2016-04-15 11:42   ` Markus Armbruster
2016-04-26 12:56     ` Eric Blake
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 16/19] qom: Wrap prop " Eric Blake
2016-04-15 11:52   ` Markus Armbruster
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 17/19] qmp-input: Require struct push to visit members of top dict Eric Blake
2016-04-15 12:53   ` Markus Armbruster
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 18/19] qapi: Simplify semantics of visit_next_list() Eric Blake
2016-04-15 14:09   ` Markus Armbruster
2016-04-22  8:46     ` Markus Armbruster
2016-04-22 11:35       ` Markus Armbruster
2016-04-22 11:37         ` [Qemu-devel] [PATCH] tests/string-input-visitor: Add negative integer tests Markus Armbruster
2016-04-27 20:22         ` [Qemu-devel] [PATCH v14 18/19] qapi: Simplify semantics of visit_next_list() Eric Blake
2016-04-08 16:13 ` [Qemu-devel] [PATCH v14 19/19] qapi: Change visit_type_FOO() to no longer return partial objects Eric Blake
2016-04-15 14:49   ` Markus Armbruster
2016-04-27 21:51     ` Eric Blake
2016-04-15 15:41 ` [Qemu-devel] [PATCH v14 00/19] qapi visitor cleanups (post-introspection cleanups subset E) 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=877ffzutw8.fsf@dusky.pond.sub.org \
    --to=armbru@redhat.com \
    --cc=eblake@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.