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 19/19] qapi: Change visit_type_FOO() to no longer return partial objects
Date: Fri, 15 Apr 2016 16:49:49 +0200 [thread overview]
Message-ID: <87lh4forjm.fsf@dusky.pond.sub.org> (raw)
In-Reply-To: <1460131992-32278-20-git-send-email-eblake@redhat.com> (Eric Blake's message of "Fri, 8 Apr 2016 10:13:12 -0600")
Eric Blake <eblake@redhat.com> writes:
> Returning a partial object on error is an invitation for a careless
> caller to leak memory. As no one outside the testsuite was actually
> relying on these semantics, it is cleaner to just document and
> guarantee that ALL pointer-based visit_type_FOO() functions always
> leave a safe value in *obj during an input visitor (either the new
> object on success, or NULL if an error is encountered), so callers
> can now unconditionally use qapi_free_FOO() to clean up regardless
> of whether an error occurred.
Hmm, wasn't the "assign null on error" part done in a prior patch?
Checking... no, only half of it, in PATCH 03: there, we went from "may
store an incomplete object on error" to "store either an incomplete
object or null on error". Now we go on to just "store null on error".
Correct?
> The decision is done by enhancing qapi-visit-core to return true
> for input visitors (the callbacks themselves do not need
> modification); since we've documented that visit_end_* must be
> called after any successful visit_start_*, that is a sufficient
> point for knowing that something was allocated during start.
I find this sentence a bit confusing. Let me try:
To help visitor-agnostic code, such as the generated qapi-visit.c,
make the visit_end_FOO() return true when something was allocated.
Easily done in the visitor core, no need to change the callbacks.
But see my comments on the visit_end_FOO() inline.
> Note that we still leave *obj unchanged after a scalar-based
> visit_type_FOO(); I did not feel like auditing all uses of
> visit_type_Enum() to see if the callers would tolerate a specific
> sentinel value (not to mention having to decide whether it would
> be better to use 0 or ENUM__MAX as that sentinel).
Should this note be in PATCH 03?
The inconsistency isn't pretty, but tolerable if it simplifies things.
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v14: no change
> v13: rebase to latest, documentation tweaks
> v12: rebase to latest, don't modify callback signatures, use newer
> approach for detecting input visitors, avoid 'allocated' boolean
> [no v10, v11]
> v9: fix bug in use of errp
> v8: rebase to earlier changes
> v7: rebase to earlier changes, enhance commit message, also fix
> visit_type_str() and visit_type_any()
> v6: rebase on top of earlier doc and formatting improvements, mention
> that *obj can be uninitialized on entry to an input visitor, rework
> semantics to keep valgrind happy on uninitialized input, break some
> long lines
> ---
> include/qapi/visitor.h | 42 ++++++++++++++++++++++++++++++------------
> include/qapi/visitor-impl.h | 8 +++++---
> scripts/qapi-visit.py | 25 +++++++++++++------------
> qapi/qapi-visit-core.c | 41 ++++++++++++++++++++++++++++++++++-------
> tests/test-qmp-commands.c | 13 ++++++-------
> tests/test-qmp-input-strict.c | 19 ++++++++-----------
> tests/test-qmp-input-visitor.c | 10 ++--------
> docs/qapi-code-gen.txt | 10 ++++++++--
> 8 files changed, 106 insertions(+), 62 deletions(-)
>
> diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
> index a22a7ce..4cc6d3a 100644
> --- a/include/qapi/visitor.h
> +++ b/include/qapi/visitor.h
> @@ -65,14 +65,16 @@
> * }' if an error is encountered on "value" (or to have the visitor
> * core auto-generate the nicer name).
> *
> - * FIXME: At present, input visitors may allocate an incomplete *@obj
> - * even when visit_type_FOO() reports an error. Using an output
> - * visitor with an incomplete object has undefined behavior; callers
> - * must call qapi_free_FOO() (which uses the dealloc visitor, and
> - * safely handles an incomplete object) to avoid a memory leak.
> + * If an error is detected during visit_type_FOO() with an input
> + * visitor, then *@obj will be NULL for pointer types, and left
> + * unchanged for scalar types.
Okay.
> + * Using an output visitor with an
> + * incomplete object has undefined behavior (other than a special case
> + * for visit_type_str() treating NULL like ""), while the dealloc
> + * visitor safely handles incomplete objects.
Where do the incomplete objects come from now? I thought this patch
gets rid of them.
> *
> - * Likewise, the QAPI object types (structs, unions, and alternates)
> - * have a generated function in qapi-visit.h compatible with:
> + * Additionally, the QAPI object types (structs, unions, and
> + * alternates) have a generated function in qapi-visit.h compatible
> + * with:
> *
> * void visit_type_FOO_members(Visitor *v, FOO *obj, Error **errp);
> *
Replaces "Likewise" by "Additionally". Why not write it this way from
the start?
> @@ -104,7 +106,6 @@
> * v = ...obtain input visitor...
> * visit_type_Foo(v, NULL, &f, &err);
> * if (err) {
> - * qapi_free_Foo(f);
> * ...handle error...
> * } else {
> * ...use f...
> @@ -112,7 +113,6 @@
> * v = ...obtain input visitor...
> * visit_type_FooList(v, NULL, &l, &err);
> * if (err) {
> - * qapi_free_FooList(l);
> * ...handle error...
> * } else {
> * while (l) {
> @@ -256,8 +256,14 @@ void visit_check_struct(Visitor *v, Error **errp);
> * even if intermediate processing was skipped due to errors, to allow
> * the backend to release any resources. Destroying the visitor may
> * behave as if this was implicitly called.
> + *
> + * Returns true if this is an input visitor (that is, an allocation
> + * occurred during visit_start_struct() if obj was non-NULL). The
> + * caller can use this, along with tracking whether a local error
> + * occurred in the meantime, to decide when to undo allocation before
> + * returning control from a visit_type_FOO() function.
> */
> -void visit_end_struct(Visitor *v);
> +bool visit_end_struct(Visitor *v);
I generally like functions to return something useful, but not in this
case, because the function name gives you no clue about its value.
Consider:
if (visit_end_struct(v) && err) {
qapi_free_FOO(*obj);
*obj = NULL;
}
To find out what this means, a reader not familiar with visitors almost
certainly needs to refer to visit_end_struct()'s contract or code.
Compare:
visit_end_struct(v);
if (err && v->type == VISITOR_INPUT) {
qapi_free_FOO(*obj);
*obj = NULL;
}
Or:
visit_end_struct(v);
if (err && visit_is_input(v)) {
qapi_free_FOO(*obj);
*obj = NULL;
}
>
>
> /* === Visiting lists */
> @@ -313,8 +319,14 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size);
> * even if intermediate processing was skipped due to errors, to allow
> * the backend to release any resources. Destroying the visitor may
> * behave as if this was implicitly called.
> + *
> + * Returns true if this is an input visitor (that is, an allocation
> + * occurred during visit_start_list() if list was non-NULL). The
> + * caller can use this, along with tracking whether a local error
> + * occurred in the meantime, to decide when to undo allocation before
> + * returning control from a visit_type_FOO() function.
> */
> -void visit_end_list(Visitor *v);
> +bool visit_end_list(Visitor *v);
>
>
> /* === Visiting alternates */
> @@ -347,10 +359,16 @@ void visit_start_alternate(Visitor *v, const char *name,
> * the backend to release any resources. Destroying the visitor may
> * behave as if this was implicitly called.
> *
> + * Returns true if this is an input visitor (that is, an allocation
> + * occurred during visit_start_alternate() if obj was non-NULL). The
> + * caller can use this, along with tracking whether a local error
> + * occurred in the meantime, to decide when to undo allocation before
> + * returning control from a visit_type_FOO() function.
> + *
> * TODO: Should all the visit_end_* interfaces take obj parameter, so
> * that dealloc visitor need not track what was passed in visit_start?
> */
> -void visit_end_alternate(Visitor *v);
> +bool visit_end_alternate(Visitor *v);
>
>
> /* === Other helpers */
> diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
> index 0471465..f113869 100644
> --- a/include/qapi/visitor-impl.h
> +++ b/include/qapi/visitor-impl.h
> @@ -42,7 +42,8 @@ struct Visitor
> /* Optional; intended for input visitors. */
> void (*check_struct)(Visitor *v, Error **errp);
>
> - /* Must be set to visit structs. */
> + /* Must be set to visit structs. The core takes care of the
> + * return value. */
> void (*end_struct)(Visitor *v);
>
> /* Must be set; document if @list may not be NULL. */
> @@ -52,7 +53,7 @@ struct Visitor
> /* Must be set. */
> GenericList *(*next_list)(Visitor *v, GenericList *tail, size_t size);
>
> - /* Must be set. */
> + /* Must be set. The core takes care of the return value. */
> void (*end_list)(Visitor *v);
>
> /* Must be set by input and dealloc visitors to visit alternates;
> @@ -61,7 +62,8 @@ struct Visitor
> GenericAlternate **obj, size_t size,
> bool promote_int, Error **errp);
>
> - /* Optional, needed for dealloc visitor. */
> + /* Optional, needed for dealloc visitor. The core takes care of
> + * the return value. */
> void (*end_alternate)(Visitor *v);
>
> /* Must be set. */
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index 69f0133..8f51d8c 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -108,10 +108,6 @@ out:
>
>
> def gen_visit_list(name, element_type):
> - # FIXME: if *obj is NULL on entry, and the first visit_next_list()
> - # assigns to *obj, while a later one fails, we should clean up *obj
> - # rather than leaving it non-NULL. As currently written, the caller must
> - # call qapi_free_FOOList() to avoid a memory leak of the partial FOOList.
> return mcgen('''
>
> void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
> @@ -131,7 +127,10 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
> break;
> }
> }
> - visit_end_list(v);
> + if (visit_end_list(v) && err) {
> + qapi_free_%(c_name)s(*obj);
> + *obj = NULL;
> + }
> out:
> error_propagate(errp, err);
> }
> @@ -208,21 +207,20 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
> error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
> "%(name)s");
> }
> - visit_end_alternate(v);
> + if (visit_end_alternate(v) && err) {
> + qapi_free_%(c_name)s(*obj);
> + *obj = NULL;
> + }
> out:
> error_propagate(errp, err);
> }
> ''',
> - name=name)
> + name=name, c_name=c_name(name))
>
> return ret
>
>
> def gen_visit_object(name, base, members, variants):
> - # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
> - # *obj, but then visit_type_FOO_members() fails, we should clean up *obj
> - # rather than leaving it non-NULL. As currently written, the caller must
> - # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
> return mcgen('''
>
> void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
> @@ -242,7 +240,10 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
> }
> visit_check_struct(v, &err);
> out_obj:
> - visit_end_struct(v);
> + if (visit_end_struct(v) && err) {
> + qapi_free_%(c_name)s(*obj);
> + *obj = NULL;
> + }
> out:
> error_propagate(errp, err);
> }
> diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
> index 622b315..8477cc0 100644
> --- a/qapi/qapi-visit-core.c
> +++ b/qapi/qapi-visit-core.c
> @@ -23,11 +23,17 @@
> void visit_start_struct(Visitor *v, const char *name, void **obj,
> size_t size, Error **errp)
> {
> + Error *err = NULL;
> +
> if (obj) {
> assert(size);
> assert(v->type != VISITOR_OUTPUT || *obj);
> }
> - v->start_struct(v, name, obj, size, errp);
> + v->start_struct(v, name, obj, size, &err);
> + if (obj && v->type == VISITOR_INPUT) {
> + assert(err || *obj);
> + }
> + error_propagate(errp, err);
Sure this belongs to this patch? More of the same below.
> }
>
> void visit_check_struct(Visitor *v, Error **errp)
> @@ -37,11 +43,13 @@ void visit_check_struct(Visitor *v, Error **errp)
> }
> }
>
> -void visit_end_struct(Visitor *v)
> +bool visit_end_struct(Visitor *v)
> {
> v->end_struct(v);
> + return v->type == VISITOR_INPUT;
> }
>
> +
> void visit_start_list(Visitor *v, const char *name, GenericList **list,
> size_t size, Error **errp)
> {
> @@ -55,26 +63,34 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size)
> return v->next_list(v, tail, size);
> }
>
> -void visit_end_list(Visitor *v)
> +bool visit_end_list(Visitor *v)
> {
> v->end_list(v);
> + return v->type == VISITOR_INPUT;
> }
>
> void visit_start_alternate(Visitor *v, const char *name,
> GenericAlternate **obj, size_t size,
> bool promote_int, Error **errp)
> {
> + Error *err = NULL;
> +
> assert(obj && size >= sizeof(GenericAlternate));
> if (v->start_alternate) {
> - v->start_alternate(v, name, obj, size, promote_int, errp);
> + v->start_alternate(v, name, obj, size, promote_int, &err);
> + if (v->type == VISITOR_INPUT) {
> + assert(err || *obj);
> + }
> + error_propagate(errp, err);
> }
> }
>
> -void visit_end_alternate(Visitor *v)
> +bool visit_end_alternate(Visitor *v)
> {
> if (v->end_alternate) {
> v->end_alternate(v);
> }
> + return v->type == VISITOR_INPUT;
> }
>
> bool visit_optional(Visitor *v, const char *name, bool *present)
> @@ -206,12 +222,17 @@ void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
>
> void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp)
> {
> + Error *err = NULL;
> assert(obj);
> /* TODO: Fix callers to not pass NULL when they mean "", so that we
> * can enable:
> assert(v->type != VISITOR_OUTPUT || *obj);
> */
> - v->type_str(v, name, obj, errp);
> + v->type_str(v, name, obj, &err);
> + if (v->type == VISITOR_INPUT) {
> + assert(err || *obj);
> + }
> + error_propagate(errp, err);
> }
>
> void visit_type_number(Visitor *v, const char *name, double *obj,
> @@ -223,9 +244,15 @@ void visit_type_number(Visitor *v, const char *name, double *obj,
>
> void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp)
> {
> + Error *err = NULL;
> +
> assert(obj);
> assert(v->type != VISITOR_OUTPUT || *obj);
> - v->type_any(v, name, obj, errp);
> + v->type_any(v, name, obj, &err);
> + if (v->type == VISITOR_INPUT) {
> + assert(err || *obj);
> + }
> + error_propagate(errp, err);
> }
>
> void visit_type_null(Visitor *v, const char *name, Error **errp)
> diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
> index 14a9ebb..d6c494d 100644
> --- a/tests/test-qmp-commands.c
> +++ b/tests/test-qmp-commands.c
> @@ -228,14 +228,13 @@ static void test_dealloc_partial(void)
> QDECREF(ud2_dict);
> }
>
> - /* verify partial success */
> - assert(ud2 != NULL);
> - assert(ud2->string0 != NULL);
> - assert(strcmp(ud2->string0, text) == 0);
> - assert(ud2->dict1 == NULL);
> -
> - /* confirm & release construction error */
> + /* verify that visit_type_XXX() cleans up properly on error */
> error_free_or_abort(&err);
> + assert(!ud2);
> +
> + /* Manually create a partial object, leaving ud2->dict1 at NULL */
> + ud2 = g_new0(UserDefTwo, 1);
> + ud2->string0 = g_strdup(text);
>
> /* tear down partial object */
> qapi_free_UserDefTwo(ud2);
Somewhat redundant now, because the free hidden in the failed visit
already covers partial object teardown. I don't mind.
> diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c
> index d71727e..e039455 100644
> --- a/tests/test-qmp-input-strict.c
> +++ b/tests/test-qmp-input-strict.c
> @@ -182,10 +182,7 @@ static void test_validate_fail_struct(TestInputVisitorData *data,
>
> visit_type_TestStruct(v, NULL, &p, &err);
> error_free_or_abort(&err);
> - if (p) {
> - g_free(p->string);
> - }
> - g_free(p);
> + g_assert(!p);
> }
>
> static void test_validate_fail_struct_nested(TestInputVisitorData *data,
> @@ -199,7 +196,7 @@ static void test_validate_fail_struct_nested(TestInputVisitorData *data,
>
> visit_type_UserDefTwo(v, NULL, &udp, &err);
> error_free_or_abort(&err);
> - qapi_free_UserDefTwo(udp);
> + g_assert(!udp);
> }
>
> static void test_validate_fail_list(TestInputVisitorData *data,
> @@ -213,7 +210,7 @@ static void test_validate_fail_list(TestInputVisitorData *data,
>
> visit_type_UserDefOneList(v, NULL, &head, &err);
> error_free_or_abort(&err);
> - qapi_free_UserDefOneList(head);
> + g_assert(!head);
> }
>
> static void test_validate_fail_union_native_list(TestInputVisitorData *data,
> @@ -228,7 +225,7 @@ static void test_validate_fail_union_native_list(TestInputVisitorData *data,
>
> visit_type_UserDefNativeListUnion(v, NULL, &tmp, &err);
> error_free_or_abort(&err);
> - qapi_free_UserDefNativeListUnion(tmp);
> + g_assert(!tmp);
> }
>
> static void test_validate_fail_union_flat(TestInputVisitorData *data,
> @@ -242,7 +239,7 @@ static void test_validate_fail_union_flat(TestInputVisitorData *data,
>
> visit_type_UserDefFlatUnion(v, NULL, &tmp, &err);
> error_free_or_abort(&err);
> - qapi_free_UserDefFlatUnion(tmp);
> + g_assert(!tmp);
> }
>
> static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data,
> @@ -257,13 +254,13 @@ static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data,
>
> visit_type_UserDefFlatUnion2(v, NULL, &tmp, &err);
> error_free_or_abort(&err);
> - qapi_free_UserDefFlatUnion2(tmp);
> + g_assert(!tmp);
> }
>
> static void test_validate_fail_alternate(TestInputVisitorData *data,
> const void *unused)
> {
> - UserDefAlternate *tmp = NULL;
> + UserDefAlternate *tmp;
Did this initialization become dead in PATCH 03 already?
> Visitor *v;
> Error *err = NULL;
>
> @@ -271,7 +268,7 @@ static void test_validate_fail_alternate(TestInputVisitorData *data,
>
> visit_type_UserDefAlternate(v, NULL, &tmp, &err);
> error_free_or_abort(&err);
> - qapi_free_UserDefAlternate(tmp);
> + g_assert(!tmp);
> }
>
> static void do_test_validate_qmp_introspect(TestInputVisitorData *data,
> diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
> index ac8ebea..0b4153a 100644
> --- a/tests/test-qmp-input-visitor.c
> +++ b/tests/test-qmp-input-visitor.c
> @@ -760,18 +760,12 @@ static void test_visitor_in_errors(TestInputVisitorData *data,
>
> visit_type_TestStruct(v, NULL, &p, &err);
> error_free_or_abort(&err);
> - /* FIXME - a failed parse should not leave a partially-allocated p
> - * for us to clean up; this could cause callers to leak memory. */
> - g_assert(p->string == NULL);
> -
> - g_free(p->string);
> - g_free(p);
> + g_assert(!p);
>
> v = visitor_input_test_init(data, "[ '1', '2', false, '3' ]");
> visit_type_strList(v, NULL, &q, &err);
> error_free_or_abort(&err);
> - assert(q);
> - qapi_free_strList(q);
> + assert(!q);
> }
>
> static void test_visitor_in_wrong_type(TestInputVisitorData *data,
> diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
> index 99080db..3b2a27f 100644
> --- a/docs/qapi-code-gen.txt
> +++ b/docs/qapi-code-gen.txt
> @@ -904,7 +904,10 @@ Example:
> }
> visit_check_struct(v, &err);
> out_obj:
> - visit_end_struct(v);
> + if (visit_end_struct(v) && err) {
> + qapi_free_UserDefOne(*obj);
> + *obj = NULL;
> + }
> out:
> error_propagate(errp, err);
> }
> @@ -927,7 +930,10 @@ Example:
> }
> }
>
> - visit_end_list(v);
> + if (visit_end_list(v) && err) {
> + qapi_free_UserDefOneList(*obj);
> + *obj = NULL;
> + }
> out:
> error_propagate(errp, err);
> }
next prev parent reply other threads:[~2016-04-15 14:50 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
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 [this message]
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=87lh4forjm.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.