From patchwork Tue Aug 18 14:19:53 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 508340 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id F303B140293 for ; Wed, 19 Aug 2015 00:24:36 +1000 (AEST) Received: from localhost ([::1]:57472 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZRhoY-0003Ue-JH for incoming@patchwork.ozlabs.org; Tue, 18 Aug 2015 10:24:34 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34171) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZRhl9-0002tN-9e for qemu-devel@nongnu.org; Tue, 18 Aug 2015 10:21:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZRhl7-0005ou-Dk for qemu-devel@nongnu.org; Tue, 18 Aug 2015 10:21:03 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39271) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZRhl6-0005oF-4I for qemu-devel@nongnu.org; Tue, 18 Aug 2015 10:21:00 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (Postfix) with ESMTPS id CD487AB0; Tue, 18 Aug 2015 14:20:59 +0000 (UTC) Received: from red.redhat.com (ovpn-113-180.phx2.redhat.com [10.3.113.180]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t7IEKBPj029844; Tue, 18 Aug 2015 10:20:57 -0400 From: Eric Blake To: qemu-devel@nongnu.org Date: Tue, 18 Aug 2015 07:19:53 -0700 Message-Id: <1439907602-11414-12-git-send-email-eblake@redhat.com> In-Reply-To: <1439907602-11414-1-git-send-email-eblake@redhat.com> References: <1439907602-11414-1-git-send-email-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: armbru@redhat.com, Michael Roth Subject: [Qemu-devel] [PATCH RFC v3 11/20] qapi: Rework deallocation of partial struct X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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, and much shorter, fix is to tweak all of the generated visit_type_implicit_FOO() functions to avoid dereferencing NULL in the first place, to not visit 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 using visit_end_union() callbacks. Also, this fixes things to guarantee that any successful call to visit_start_implicit_struct() is paired with a matching visit_end_implicit_struct(). The lack of documentation on the visitor interface is appalling, but I'm not fixing it here. Signed-off-by: Eric Blake --- include/qapi/visitor-impl.h | 2 -- include/qapi/visitor.h | 2 -- qapi/qapi-dealloc-visitor.c | 26 -------------------------- qapi/qapi-visit-core.c | 15 --------------- scripts/qapi-visit.py | 10 +++------- 5 files changed, 3 insertions(+), 52 deletions(-) diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index c94e5a1..22539df 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -57,8 +57,6 @@ struct Visitor void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error **errp); /* visit_type_size() falls back to (*type_uint64)() if type_size is unset */ void (*type_size)(Visitor *v, uint64_t *obj, const char *name, Error **errp); - bool (*start_union)(Visitor *v, bool data_present, Error **errp); - void (*end_union)(Visitor *v, bool data_present, Error **errp); }; void input_type_enum(Visitor *v, int *obj, const char * const strings[], diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 6a93c87..d1e853c 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -59,7 +59,5 @@ void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp); void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp); void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp); void visit_type_any(Visitor *v, QObject **obj, const char *name, Error **errp); -bool visit_start_union(Visitor *v, bool data_present, Error **errp); -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 737deab..4989f50 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_number = qapi_dealloc_type_number; v->visitor.type_any = qapi_dealloc_type_anything; v->visitor.type_size = qapi_dealloc_type_size; - 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 884fe94..82bfdd0 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -58,21 +58,6 @@ void visit_end_list(Visitor *v, Error **errp) v->end_list(v, errp); } -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); - } -} - void visit_optional(Visitor *v, bool *present, const char *name, Error **errp) { diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 58afb2d..08dfd59 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -49,7 +49,9 @@ static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error * visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err); if (!err) { - visit_type_%(c_type)s_fields(m, obj, &err); + if (!obj || *obj) { + visit_type_%(c_type)s_fields(m, obj, &err); + } visit_end_implicit_struct(m, err ? NULL : &err); } error_propagate(errp, err); @@ -286,9 +288,6 @@ void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error c_type=variants.tag_member.type.c_name(), c_name=c_name(tag_key), name=tag_key) ret += mcgen(''' - if (!visit_start_union(m, !!(*obj)->data, &err) || err) { - goto out_obj; - } switch ((*obj)->%(c_name)s) { ''', c_name=c_name(tag_key)) @@ -321,9 +320,6 @@ void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error abort(); } out_obj: - error_propagate(errp, err); - err = NULL; - visit_end_union(m, !!(*obj)->data, &err); visit_end_struct(m, err ? NULL : &err); out: error_propagate(errp, err);