From: Eric Blake <eblake@redhat.com>
To: qemu-devel@nongnu.org
Cc: armbru@redhat.com, Michael Roth <mdroth@linux.vnet.ibm.com>
Subject: [Qemu-devel] [PATCH v6 20/23] qapi: Rework deallocation of partial struct
Date: Wed, 25 Nov 2015 17:23:17 -0700 [thread overview]
Message-ID: <1448497401-27784-21-git-send-email-eblake@redhat.com> (raw)
In-Reply-To: <1448497401-27784-1-git-send-email-eblake@redhat.com>
Commit cee2dedb noticed that if you have a partial flat union
(such as if an input parse failed due to a missing
discriminator), calling the dealloc visitor could result in
trying to dereference the NULL pointer. But the fix it proposed
requires the use of a 'data' member in the union, which may or
may not be the same size as other branches of the union
(consider a 32-bit platform where one of the branches is an
int64), so it feels fairly dirty. A better fix is to tweak all
of the generated visit_type_implicit_FOO() functions to avoid
dereferencing NULL in the first place, by not visiting the
fields if the struct pointer itself is not present, at which
point we no longer even need visit_start_union(). And no one
was implementing visit_end_union() callbacks.
While rewriting the code, use patterns that are closer to what
is used elsewhere in the generated visitors, by using 'goto'
to cleanup labels rather than putting followup code under 'if'
conditions. The change keeps the contract that any successful
use of visit_start_implicit_struct() will be paired with a
matching visit_end_implicit_struct(), even if intermediate
processing is skipped.
As an example of the changes to generated code:
|@@ -1331,10 +1331,16 @@ static void visit_type_implicit_Blockdev
| Error *err = NULL;
|
| visit_start_implicit_struct(v, (void **)obj, sizeof(BlockdevOptionsArchipelago), &err);
|- if (!err) {
|- visit_type_BlockdevOptionsArchipelago_fields(v, obj, errp);
|- visit_end_implicit_struct(v);
|+ if (err) {
|+ goto out;
|+ }
|+ if (obj && !*obj) {
|+ goto out_obj;
| }
|+ visit_type_BlockdevOptionsArchipelago_fields(v, obj, &err);
|+out_obj:
|+ visit_end_implicit_struct(v);
|+out:
| error_propagate(errp, err);
| }
...
|@@ -1479,9 +1539,6 @@ void visit_type_BlockdevOptions(Visitor
| if (err) {
| goto out_obj;
| }
|- if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
|- goto out_obj;
|- }
| switch ((*obj)->driver) {
| case BLOCKDEV_DRIVER_ARCHIPELAGO:
| visit_type_implicit_BlockdevOptionsArchipelago(v, &(*obj)->u.archipelago, &err);
|@@ -1570,11 +1627,6 @@ void visit_type_BlockdevOptions(Visitor
| out_obj:
| error_propagate(errp, err);
| err = NULL;
|- if (*obj) {
|- visit_end_union(v, !!(*obj)->u.data, &err);
|- }
|- error_propagate(errp, err);
|- err = NULL;
| visit_end_struct(v, &err);
Signed-off-by: Eric Blake <eblake@redhat.com>
---
v6: rebase due to deferring 7/46, and gen_err_check() improvements;
rewrite gen_visit_implicit_struct() more like other patterns
---
include/qapi/visitor-impl.h | 5 -----
include/qapi/visitor.h | 12 ------------
qapi/qapi-dealloc-visitor.c | 26 --------------------------
qapi/qapi-visit-core.c | 15 ---------------
scripts/qapi-visit.py | 25 +++++++++----------------
5 files changed, 9 insertions(+), 74 deletions(-)
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index 36984a7..018f419 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -78,11 +78,6 @@ struct Visitor
/* May be NULL; most useful for input visitors. */
void (*optional)(Visitor *v, bool *present, const char *name);
-
- /* FIXME - needs to be removed */
- bool (*start_union)(Visitor *v, bool data_present, Error **errp);
- /* FIXME - needs to be removed */
- void (*end_union)(Visitor *v, bool data_present, Error **errp);
};
/**
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index b4ed469..cc1ff6d 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -236,16 +236,4 @@ void visit_type_number(Visitor *v, double *obj, const char *name,
*/
void visit_type_any(Visitor *v, QObject **obj, const char *name, Error **errp);
-/**
- * Mark the start of visiting the branches of a union. Return true if
- * @data_present.
- * FIXME: Should not be needed
- */
-bool visit_start_union(Visitor *v, bool data_present, Error **errp);
-/**
- * Mark the end of union branches, after visit_start_union().
- * FIXME: Should not be needed
- */
-void visit_end_union(Visitor *v, bool data_present, Error **errp);
-
#endif
diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
index 8246070..8b489a4 100644
--- a/qapi/qapi-dealloc-visitor.c
+++ b/qapi/qapi-dealloc-visitor.c
@@ -171,31 +171,6 @@ static void qapi_dealloc_type_enum(Visitor *v, int *obj,
{
}
-/* If there's no data present, the dealloc visitor has nothing to free.
- * Thus, indicate to visitor code that the subsequent union fields can
- * be skipped. This is not an error condition, since the cleanup of the
- * rest of an object can continue unhindered, so leave errp unset in
- * these cases.
- *
- * NOTE: In cases where we're attempting to deallocate an object that
- * may have missing fields, the field indicating the union type may
- * be missing. In such a case, it's possible we don't have enough
- * information to differentiate data_present == false from a case where
- * data *is* present but happens to be a scalar with a value of 0.
- * This is okay, since in the case of the dealloc visitor there's no
- * work that needs to done in either situation.
- *
- * The current inability in QAPI code to more thoroughly verify a union
- * type in such cases will likely need to be addressed if we wish to
- * implement this interface for other types of visitors in the future,
- * however.
- */
-static bool qapi_dealloc_start_union(Visitor *v, bool data_present,
- Error **errp)
-{
- return data_present;
-}
-
Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
{
return &v->visitor;
@@ -226,7 +201,6 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
v->visitor.type_str = qapi_dealloc_type_str;
v->visitor.type_number = qapi_dealloc_type_number;
v->visitor.type_any = qapi_dealloc_type_anything;
- v->visitor.start_union = qapi_dealloc_start_union;
QTAILQ_INIT(&v->stack);
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 477d73a..a193a04 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -58,21 +58,6 @@ void visit_end_list(Visitor *v)
v->end_list(v);
}
-bool visit_start_union(Visitor *v, bool data_present, Error **errp)
-{
- if (v->start_union) {
- return v->start_union(v, data_present, errp);
- }
- return true;
-}
-
-void visit_end_union(Visitor *v, bool data_present, Error **errp)
-{
- if (v->end_union) {
- v->end_union(v, data_present, errp);
- }
-}
-
bool visit_optional(Visitor *v, bool *present, const char *name)
{
if (v->optional) {
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index f22ebeb..43233d6 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -60,10 +60,16 @@ static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error *
Error *err = NULL;
visit_start_implicit_struct(v, (void **)obj, sizeof(%(c_type)s), &err);
- if (!err) {
- visit_type_%(c_type)s_fields(v, obj, errp);
- visit_end_implicit_struct(v);
+ if (err) {
+ goto out;
}
+ if (obj && !*obj) {
+ goto out_obj;
+ }
+ visit_type_%(c_type)s_fields(v, obj, &err);
+out_obj:
+ visit_end_implicit_struct(v);
+out:
error_propagate(errp, err);
}
''',
@@ -254,9 +260,6 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
if variants:
ret += mcgen('''
- if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
- goto out_obj;
- }
switch ((*obj)->%(c_name)s) {
''',
c_name=c_name(variants.tag_member.name))
@@ -293,16 +296,6 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
ret += mcgen('''
out_obj:
-''')
- if variants:
- ret += mcgen('''
- error_propagate(errp, err);
- err = NULL;
- if (*obj) {
- visit_end_union(v, !!(*obj)->u.data, &err);
- }
-''')
- ret += mcgen('''
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
--
2.4.3
next prev parent reply other threads:[~2015-11-26 0:23 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-11-26 0:22 [Qemu-devel] [PATCH v6 00/23] qapi visitor cleanups (post-introspection cleanups subset E) Eric Blake
2015-11-26 0:22 ` [Qemu-devel] [PATCH v6 01/23] qapi: Make all visitors supply int64/uint64 callbacks Eric Blake
2015-11-27 11:17 ` Markus Armbruster
2015-11-26 0:22 ` [Qemu-devel] [PATCH v6 02/23] qapi: Require int64/uint64 implementation Eric Blake
2015-11-27 12:05 ` Markus Armbruster
2015-12-02 21:25 ` Eric Blake
2015-12-03 8:30 ` Markus Armbruster
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 03/23] qapi: Consolidate visitor integer callbacks Eric Blake
2015-11-27 12:11 ` Markus Armbruster
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 04/23] qapi: Don't cast Enum* to int* Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 05/23] qmp: Fix reference-counting of qnull on empty output visit Eric Blake
2015-11-27 13:06 ` Markus Armbruster
2015-12-02 23:10 ` Eric Blake
2015-12-03 17:50 ` Markus Armbruster
2015-12-04 3:01 ` Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 06/23] qapi: Don't abuse stack to track qmp-output root Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 07/23] qapi: Document visitor interfaces Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 08/23] qapi: Drop unused error argument for list and implicit struct Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 09/23] hmp: Improve use of qapi visitor Eric Blake
2015-12-04 21:18 ` Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 10/23] vl: " Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 11/23] ppc: Improve use of qapi visitors Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 12/23] balloon: Improve use of qapi visitor Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 13/23] qapi: Add type.is_empty() helper Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 14/23] qapi: Fix command with named empty argument type Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 15/23] qapi: Improve generated event use of qapi visitor Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 16/23] qapi: Track all failures between visit_start/stop Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 17/23] qapi: Eliminate empty visit_type_FOO_fields Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 18/23] qapi: Canonicalize missing object to :empty Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 19/23] qapi-visit: Unify struct and union visit Eric Blake
2015-11-26 0:23 ` Eric Blake [this message]
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 21/23] qapi: Simplify extra member error reporting in input visitors Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 22/23] qapi: Split visit_end_struct() into pieces Eric Blake
2015-11-26 0:23 ` [Qemu-devel] [PATCH v6 23/23] qapi: Change visit_type_FOO() to no longer return partial objects Eric Blake
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=1448497401-27784-21-git-send-email-eblake@redhat.com \
--to=eblake@redhat.com \
--cc=armbru@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).