From f9bee751be1292c9433a95d835474dc38a134a95 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 7 May 2014 09:53:44 +0200 Subject: qapi: Normalize marshalling's visitor initialization and cleanup Input and output marshalling functions do it differently. Change them to work the same: initialize the I/O visitor, use it, clean it up, initialize the dealloc visitor, use it, clean it up. This delays dealloc visitor initialization in output marshalling functions, and input visitor cleanup in input marshalling functions. No functional change, but the latter will be convenient when I change the error handling. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Luiz Capitulino --- scripts/qapi-commands.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'scripts/qapi-commands.py') diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 8d9096f65c..1399826cca 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -69,16 +69,17 @@ def gen_marshal_output_call(name, ret_type): return "" return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name) -def gen_visitor_input_containers_decl(args): +def gen_visitor_input_containers_decl(args, obj): ret = "" push_indent() if len(args) > 0: ret += mcgen(''' -QmpInputVisitor *mi; +QmpInputVisitor *mi = qmp_input_visitor_new_strict(%(obj)s); QapiDeallocVisitor *md; Visitor *v; -''') +''', + obj=obj) pop_indent() return ret.rstrip() @@ -106,7 +107,7 @@ bool has_%(argname)s = false; pop_indent() return ret.rstrip() -def gen_visitor_input_block(args, obj, dealloc=False): +def gen_visitor_input_block(args, dealloc=False): ret = "" errparg = 'errp' @@ -118,15 +119,14 @@ def gen_visitor_input_block(args, obj, dealloc=False): if dealloc: errparg = 'NULL' ret += mcgen(''' +qmp_input_visitor_cleanup(mi); md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); ''') else: ret += mcgen(''' -mi = qmp_input_visitor_new_strict(%(obj)s); v = qmp_input_get_visitor(mi); -''', - obj=obj) +''') for argname, argtype, optional, structured in parse_args(args): if optional: @@ -151,10 +151,6 @@ visit_end_optional(v, %(errp)s); if dealloc: ret += mcgen(''' qapi_dealloc_visitor_cleanup(md); -''') - else: - ret += mcgen(''' -qmp_input_visitor_cleanup(mi); ''') pop_indent() return ret.rstrip() @@ -166,8 +162,8 @@ def gen_marshal_output(name, args, ret_type, middle_mode): ret = mcgen(''' static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp) { - QapiDeallocVisitor *md = qapi_dealloc_visitor_new(); QmpOutputVisitor *mo = qmp_output_visitor_new(); + QapiDeallocVisitor *md; Visitor *v; v = qmp_output_get_visitor(mo); @@ -176,6 +172,7 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o *ret_out = qmp_output_get_qobject(mo); } qmp_output_visitor_cleanup(mo); + md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); %(visitor)s(v, &ret_in, "unused", NULL); qapi_dealloc_visitor_cleanup(md); @@ -228,9 +225,9 @@ def gen_marshal_input(name, args, ret_type, middle_mode): %(visitor_input_block)s ''', - visitor_input_containers_decl=gen_visitor_input_containers_decl(args), + visitor_input_containers_decl=gen_visitor_input_containers_decl(args, "QOBJECT(args)"), visitor_input_vars_decl=gen_visitor_input_vars_decl(args), - visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)")) + visitor_input_block=gen_visitor_input_block(args)) else: ret += mcgen(''' (void)args; @@ -250,7 +247,7 @@ out: ret += mcgen(''' %(visitor_input_block_cleanup)s ''', - visitor_input_block_cleanup=gen_visitor_input_block(args, None, + visitor_input_block_cleanup=gen_visitor_input_block(args, dealloc=True)) if middle_mode: -- cgit v1.2.3-59-g8ed1b From e2cd0f4fb42b1fae65ad22e8efde9804446e6254 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 7 May 2014 09:53:46 +0200 Subject: qapi: Replace start_optional()/end_optional() by optional() Semantics of end_optional() differ subtly from the other end_FOO() callbacks: when start_FOO() succeeds, the matching end_FOO() gets called regardless of what happens in between. end_optional() gets called only when everything in between succeeds as well. Entirely undocumented, like all of the visitor API. The only user of Visitor Callback end_optional() never did anything, and was removed in commit 9f9ab46. I'm about to clean up error handling in the generated visitor code, and end_optional() is in my way. No users mean no test cases, and making non-trivial cleanup transformations without test cases doesn't strike me as a good idea. Drop end_optional(), and rename start_optional() to optional(). We can always go back to a pair of callbacks when we have an actual need. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Luiz Capitulino --- include/qapi/visitor-impl.h | 5 ++--- include/qapi/visitor.h | 5 ++--- qapi/opts-visitor.c | 5 ++--- qapi/qapi-visit-core.c | 15 ++++----------- qapi/qmp-input-visitor.c | 6 +++--- qapi/string-input-visitor.c | 6 +++--- scripts/qapi-commands.py | 5 ++--- scripts/qapi-visit.py | 3 +-- 8 files changed, 19 insertions(+), 31 deletions(-) (limited to 'scripts/qapi-commands.py') diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index 166aaddd29..ecc0183196 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -42,9 +42,8 @@ struct Visitor Error **errp); /* May be NULL */ - void (*start_optional)(Visitor *v, bool *present, const char *name, - Error **errp); - void (*end_optional)(Visitor *v, Error **errp); + void (*optional)(Visitor *v, bool *present, const char *name, + Error **errp); void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp); void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp); diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 29da211b47..4a0178fa46 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -39,9 +39,8 @@ void visit_end_implicit_struct(Visitor *v, Error **errp); void visit_start_list(Visitor *v, const char *name, Error **errp); GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp); void visit_end_list(Visitor *v, Error **errp); -void visit_start_optional(Visitor *v, bool *present, const char *name, - Error **errp); -void visit_end_optional(Visitor *v, Error **errp); +void visit_optional(Visitor *v, bool *present, const char *name, + Error **errp); void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, const char *name, Error **errp); void visit_type_enum(Visitor *v, int *obj, const char *strings[], diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 87c1c789c9..16382e7a65 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -484,8 +484,7 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp) static void -opts_start_optional(Visitor *v, bool *present, const char *name, - Error **errp) +opts_optional(Visitor *v, bool *present, const char *name, Error **errp) { OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); @@ -528,7 +527,7 @@ opts_visitor_new(const QemuOpts *opts) /* type_number() is not filled in, but this is not the first visitor to * skip some mandatory methods... */ - ov->visitor.start_optional = &opts_start_optional; + ov->visitor.optional = &opts_optional; ov->opts_root = opts; diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 1f7475c0f3..ffd76372d1 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -69,18 +69,11 @@ void visit_end_list(Visitor *v, Error **errp) v->end_list(v, errp); } -void visit_start_optional(Visitor *v, bool *present, const char *name, - Error **errp) +void visit_optional(Visitor *v, bool *present, const char *name, + Error **errp) { - if (!error_is_set(errp) && v->start_optional) { - v->start_optional(v, present, name, errp); - } -} - -void visit_end_optional(Visitor *v, Error **errp) -{ - if (!error_is_set(errp) && v->end_optional) { - v->end_optional(v, errp); + if (!error_is_set(errp) && v->optional) { + v->optional(v, present, name, errp); } } diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index a2bed1ef10..d8612062f1 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -286,8 +286,8 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name, } } -static void qmp_input_start_optional(Visitor *v, bool *present, - const char *name, Error **errp) +static void qmp_input_optional(Visitor *v, bool *present, const char *name, + Error **errp) { QmpInputVisitor *qiv = to_qiv(v); QObject *qobj = qmp_input_get_object(qiv, name, true); @@ -329,7 +329,7 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj) v->visitor.type_bool = qmp_input_type_bool; v->visitor.type_str = qmp_input_type_str; v->visitor.type_number = qmp_input_type_number; - v->visitor.start_optional = qmp_input_start_optional; + v->visitor.optional = qmp_input_optional; v->visitor.get_next_type = qmp_input_get_next_type; qmp_input_push(v, obj, NULL); diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c index 793548ae3a..5780944792 100644 --- a/qapi/string-input-visitor.c +++ b/qapi/string-input-visitor.c @@ -120,8 +120,8 @@ static void parse_type_number(Visitor *v, double *obj, const char *name, *obj = val; } -static void parse_start_optional(Visitor *v, bool *present, - const char *name, Error **errp) +static void parse_optional(Visitor *v, bool *present, const char *name, + Error **errp) { StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); @@ -155,7 +155,7 @@ StringInputVisitor *string_input_visitor_new(const char *str) v->visitor.type_bool = parse_type_bool; v->visitor.type_str = parse_type_str; v->visitor.type_number = parse_type_number; - v->visitor.start_optional = parse_start_optional; + v->visitor.optional = parse_optional; v->string = str; return v; diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 1399826cca..341dba27a8 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -131,7 +131,7 @@ v = qmp_input_get_visitor(mi); for argname, argtype, optional, structured in parse_args(args): if optional: ret += mcgen(''' -visit_start_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s); +visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s); if (has_%(c_name)s) { ''', c_name=c_var(argname), name=argname, errp=errparg) @@ -145,8 +145,7 @@ if (has_%(c_name)s) { pop_indent() ret += mcgen(''' } -visit_end_optional(v, %(errp)s); -''', errp=errparg) +''') if dealloc: ret += mcgen(''' diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index c6579beed5..9f22eee873 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -61,7 +61,7 @@ if (!err) { for argname, argentry, optional, structured in parse_args(members): if optional: ret += mcgen(''' -visit_start_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err); +visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err); if ((*obj)->%(prefix)shas_%(c_name)s) { ''', c_prefix=c_var(field_prefix), prefix=field_prefix, @@ -82,7 +82,6 @@ visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err); pop_indent() ret += mcgen(''' } -visit_end_optional(m, &err); ''') pop_indent() -- cgit v1.2.3-59-g8ed1b From 297a3646c2947ee64a6d42ca264039732c6218e0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 7 May 2014 09:53:54 +0200 Subject: qapi: Replace uncommon use of the error API by the common one We commonly use the error API like this: err = NULL; foo(..., &err); if (err) { goto out; } bar(..., &err); Every error source is checked separately. The second function is only called when the first one succeeds. Both functions are free to pass their argument to error_set(). Because error_set() asserts no error has been set, this effectively means they must not be called with an error set. The qapi-generated code uses the error API differently: // *errp was initialized to NULL somewhere up the call chain frob(..., errp); gnat(..., errp); Errors accumulate in *errp: first error wins, subsequent errors get dropped. To make this work, the second function does nothing when called with an error set. Requires non-null errp, or else the second function can't see the first one fail. This usage has also bled into visitor tests, and two device model object property getters rtc_get_date() and balloon_stats_get_all(). With the "accumulate" technique, you need fewer error checks in callers, and buy that with an error check in every callee. Can be nice. However, mixing the two techniques is confusing. You can't use the "accumulate" technique with functions designed for the "check separately" technique. You can use the "check separately" technique with functions designed for the "accumulate" technique, but then error_set() can't catch you setting an error more than once. Standardize on the "check separately" technique for now, because it's overwhelmingly prevalent. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Luiz Capitulino --- docs/qapi-code-gen.txt | 87 ++++++++------ hw/timer/mc146818rtc.c | 24 +++- hw/virtio/virtio-balloon.c | 12 +- qapi/qapi-visit-core.c | 231 ++++++++++++++++--------------------- scripts/qapi-commands.py | 57 ++++++--- scripts/qapi-visit.py | 171 +++++++++++++-------------- tests/test-qmp-input-strict.c | 10 +- tests/test-qmp-input-visitor.c | 26 +++-- tests/test-qmp-output-visitor.c | 10 +- tests/test-visitor-serialization.c | 12 +- 10 files changed, 354 insertions(+), 286 deletions(-) (limited to 'scripts/qapi-commands.py') diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 1a635e2572..1948946c05 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -275,7 +275,6 @@ Example: qapi_dealloc_visitor_cleanup(md); } - void qapi_free_UserDefOne(UserDefOne * obj) { QapiDeallocVisitor *md; @@ -352,49 +351,54 @@ Example: { Error *err = NULL; visit_type_int(m, &(*obj)->integer, "integer", &err); + if (err) { + goto out; + } visit_type_str(m, &(*obj)->string, "string", &err); + if (err) { + goto out; + } + out: error_propagate(errp, err); } void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp) { - if (!error_is_set(errp)) { - Error *err = NULL; - visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err); - if (!err) { - if (*obj) { - visit_type_UserDefOne_fields(m, obj, &err); - error_propagate(errp, err); - err = NULL; - } - /* Always call end_struct if start_struct succeeded. */ - visit_end_struct(m, &err); + Error *err = NULL; + + visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err); + if (!err) { + if (*obj) { + visit_type_UserDefOne_fields(m, obj, errp); } - error_propagate(errp, err); + visit_end_struct(m, &err); } + error_propagate(errp, err); } void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp) { - GenericList *i, **prev = (GenericList **)obj; Error *err = NULL; + GenericList *i, **prev; - if (!error_is_set(errp)) { - visit_start_list(m, name, &err); - if (!err) { - for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) { - UserDefOneList *native_i = (UserDefOneList *)i; - visit_type_UserDefOne(m, &native_i->value, NULL, &err); - } - error_propagate(errp, err); - err = NULL; - - /* Always call end_list if start_list succeeded. */ - visit_end_list(m, &err); - } - error_propagate(errp, err); + visit_start_list(m, name, &err); + if (err) { + goto out; + } + + for (prev = (GenericList **)obj; + !err && (i = visit_next_list(m, prev, &err)) != NULL; + prev = &i) { + UserDefOneList *native_i = (UserDefOneList *)i; + visit_type_UserDefOne(m, &native_i->value, NULL, &err); } + + error_propagate(errp, err); + err = NULL; + visit_end_list(m, &err); + out: + error_propagate(errp, err); } mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h [Uninteresting stuff omitted...] @@ -434,15 +438,20 @@ Example: static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp) { + Error *local_err = NULL; QmpOutputVisitor *mo = qmp_output_visitor_new(); QapiDeallocVisitor *md; Visitor *v; v = qmp_output_get_visitor(mo); - visit_type_UserDefOne(v, &ret_in, "unused", errp); - if (!error_is_set(errp)) { - *ret_out = qmp_output_get_qobject(mo); + visit_type_UserDefOne(v, &ret_in, "unused", &local_err); + if (local_err) { + goto out; } + *ret_out = qmp_output_get_qobject(mo); + + out: + error_propagate(errp, local_err); qmp_output_visitor_cleanup(mo); md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); @@ -452,6 +461,7 @@ Example: static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp) { + Error *local_err = NULL; UserDefOne * retval = NULL; QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args)); QapiDeallocVisitor *md; @@ -459,17 +469,20 @@ Example: UserDefOne * arg1 = NULL; v = qmp_input_get_visitor(mi); - visit_type_UserDefOne(v, &arg1, "arg1", errp); - - if (error_is_set(errp)) { + visit_type_UserDefOne(v, &arg1, "arg1", &local_err); + if (local_err) { goto out; } - retval = qmp_my_command(arg1, errp); - if (!error_is_set(errp)) { - qmp_marshal_output_my_command(retval, ret, errp); + + retval = qmp_my_command(arg1, &local_err); + if (local_err) { + goto out; } + qmp_marshal_output_my_command(retval, ret, &local_err); + out: + error_propagate(errp, local_err); qmp_input_visitor_cleanup(mi); md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 6c3e3b6d75..df54546562 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -804,13 +804,33 @@ static void rtc_get_date(Object *obj, Visitor *v, void *opaque, goto out; } visit_type_int32(v, ¤t_tm.tm_year, "tm_year", &err); + if (err) { + goto out_end; + } visit_type_int32(v, ¤t_tm.tm_mon, "tm_mon", &err); + if (err) { + goto out_end; + } visit_type_int32(v, ¤t_tm.tm_mday, "tm_mday", &err); + if (err) { + goto out_end; + } visit_type_int32(v, ¤t_tm.tm_hour, "tm_hour", &err); + if (err) { + goto out_end; + } visit_type_int32(v, ¤t_tm.tm_min, "tm_min", &err); + if (err) { + goto out_end; + } visit_type_int32(v, ¤t_tm.tm_sec, "tm_sec", &err); - visit_end_struct(v, &err); - + if (err) { + goto out_end; + } +out_end: + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, errp); out: error_propagate(errp, err); } diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index ca99bd5f97..bf2b588b24 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -121,23 +121,27 @@ static void balloon_stats_get_all(Object *obj, struct Visitor *v, if (err) { goto out; } - visit_type_int(v, &s->stats_last_update, "last-update", &err); + if (err) { + goto out_end; + } visit_start_struct(v, NULL, NULL, "stats", 0, &err); if (err) { goto out_end; } - - for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) { + for (i = 0; !err && i < VIRTIO_BALLOON_S_NR; i++) { visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i], &err); } + error_propagate(errp, err); + err = NULL; visit_end_struct(v, &err); out_end: + error_propagate(errp, err); + err = NULL; visit_end_struct(v, &err); - out: error_propagate(errp, err); } diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index ffd76372d1..55f8d4068c 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -20,28 +20,24 @@ void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp) { - if (!error_is_set(errp)) { - v->start_struct(v, obj, kind, name, size, errp); - } + v->start_struct(v, obj, kind, name, size, errp); } void visit_end_struct(Visitor *v, Error **errp) { - assert(!error_is_set(errp)); v->end_struct(v, errp); } void visit_start_implicit_struct(Visitor *v, void **obj, size_t size, Error **errp) { - if (!error_is_set(errp) && v->start_implicit_struct) { + if (v->start_implicit_struct) { v->start_implicit_struct(v, obj, size, errp); } } void visit_end_implicit_struct(Visitor *v, Error **errp) { - assert(!error_is_set(errp)); if (v->end_implicit_struct) { v->end_implicit_struct(v, errp); } @@ -49,30 +45,23 @@ void visit_end_implicit_struct(Visitor *v, Error **errp) void visit_start_list(Visitor *v, const char *name, Error **errp) { - if (!error_is_set(errp)) { - v->start_list(v, name, errp); - } + v->start_list(v, name, errp); } GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp) { - if (!error_is_set(errp)) { - return v->next_list(v, list, errp); - } - - return 0; + return v->next_list(v, list, errp); } void visit_end_list(Visitor *v, Error **errp) { - assert(!error_is_set(errp)); v->end_list(v, errp); } void visit_optional(Visitor *v, bool *present, const char *name, Error **errp) { - if (!error_is_set(errp) && v->optional) { + if (v->optional) { v->optional(v, present, name, errp); } } @@ -80,7 +69,7 @@ void visit_optional(Visitor *v, bool *present, const char *name, void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, const char *name, Error **errp) { - if (!error_is_set(errp) && v->get_next_type) { + if (v->get_next_type) { v->get_next_type(v, obj, qtypes, name, errp); } } @@ -88,192 +77,172 @@ void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, void visit_type_enum(Visitor *v, int *obj, const char *strings[], const char *kind, const char *name, Error **errp) { - if (!error_is_set(errp)) { - v->type_enum(v, obj, strings, kind, name, errp); - } + v->type_enum(v, obj, strings, kind, name, errp); } void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) { - if (!error_is_set(errp)) { - v->type_int(v, obj, name, errp); - } + v->type_int(v, obj, name, errp); } void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp) { int64_t value; - if (!error_is_set(errp)) { - if (v->type_uint8) { - v->type_uint8(v, obj, name, errp); - } else { - value = *obj; - v->type_int(v, &value, name, errp); - if (value < 0 || value > UINT8_MAX) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", - "uint8_t"); - return; - } - *obj = value; + + if (v->type_uint8) { + v->type_uint8(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < 0 || value > UINT8_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "uint8_t"); + return; } + *obj = value; } } void visit_type_uint16(Visitor *v, uint16_t *obj, const char *name, Error **errp) { int64_t value; - if (!error_is_set(errp)) { - if (v->type_uint16) { - v->type_uint16(v, obj, name, errp); - } else { - value = *obj; - v->type_int(v, &value, name, errp); - if (value < 0 || value > UINT16_MAX) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", - "uint16_t"); - return; - } - *obj = value; + + if (v->type_uint16) { + v->type_uint16(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < 0 || value > UINT16_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "uint16_t"); + return; } + *obj = value; } } void visit_type_uint32(Visitor *v, uint32_t *obj, const char *name, Error **errp) { int64_t value; - if (!error_is_set(errp)) { - if (v->type_uint32) { - v->type_uint32(v, obj, name, errp); - } else { - value = *obj; - v->type_int(v, &value, name, errp); - if (value < 0 || value > UINT32_MAX) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", - "uint32_t"); - return; - } - *obj = value; + + if (v->type_uint32) { + v->type_uint32(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < 0 || value > UINT32_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "uint32_t"); + return; } + *obj = value; } } void visit_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp) { int64_t value; - if (!error_is_set(errp)) { - if (v->type_uint64) { - v->type_uint64(v, obj, name, errp); - } else { - value = *obj; - v->type_int(v, &value, name, errp); - *obj = value; - } + + if (v->type_uint64) { + v->type_uint64(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + *obj = value; } } void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp) { int64_t value; - if (!error_is_set(errp)) { - if (v->type_int8) { - v->type_int8(v, obj, name, errp); - } else { - value = *obj; - v->type_int(v, &value, name, errp); - if (value < INT8_MIN || value > INT8_MAX) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", - "int8_t"); - return; - } - *obj = value; + + if (v->type_int8) { + v->type_int8(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < INT8_MIN || value > INT8_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "int8_t"); + return; } + *obj = value; } } void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp) { int64_t value; - if (!error_is_set(errp)) { - if (v->type_int16) { - v->type_int16(v, obj, name, errp); - } else { - value = *obj; - v->type_int(v, &value, name, errp); - if (value < INT16_MIN || value > INT16_MAX) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", - "int16_t"); - return; - } - *obj = value; + + if (v->type_int16) { + v->type_int16(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < INT16_MIN || value > INT16_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "int16_t"); + return; } + *obj = value; } } void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp) { int64_t value; - if (!error_is_set(errp)) { - if (v->type_int32) { - v->type_int32(v, obj, name, errp); - } else { - value = *obj; - v->type_int(v, &value, name, errp); - if (value < INT32_MIN || value > INT32_MAX) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", - "int32_t"); - return; - } - *obj = value; + + if (v->type_int32) { + v->type_int32(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < INT32_MIN || value > INT32_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "int32_t"); + return; } + *obj = value; } } void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp) { - if (!error_is_set(errp)) { - if (v->type_int64) { - v->type_int64(v, obj, name, errp); - } else { - v->type_int(v, obj, name, errp); - } + if (v->type_int64) { + v->type_int64(v, obj, name, errp); + } else { + v->type_int(v, obj, name, errp); } } void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp) { int64_t value; - if (!error_is_set(errp)) { - if (v->type_size) { - v->type_size(v, obj, name, errp); - } else if (v->type_uint64) { - v->type_uint64(v, obj, name, errp); - } else { - value = *obj; - v->type_int(v, &value, name, errp); - *obj = value; - } + + if (v->type_size) { + v->type_size(v, obj, name, errp); + } else if (v->type_uint64) { + v->type_uint64(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + *obj = value; } } void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) { - if (!error_is_set(errp)) { - v->type_bool(v, obj, name, errp); - } + v->type_bool(v, obj, name, errp); } void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp) { - if (!error_is_set(errp)) { - v->type_str(v, obj, name, errp); - } + v->type_str(v, obj, name, errp); } void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp) { - if (!error_is_set(errp)) { - v->type_number(v, obj, name, errp); - } + v->type_number(v, obj, name, errp); } void output_type_enum(Visitor *v, int *obj, const char *strings[], @@ -299,13 +268,15 @@ void input_type_enum(Visitor *v, int *obj, const char *strings[], const char *kind, const char *name, Error **errp) { + Error *local_err = NULL; int64_t value = 0; char *enum_str; assert(strings); - visit_type_str(v, &enum_str, name, errp); - if (error_is_set(errp)) { + visit_type_str(v, &enum_str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 341dba27a8..386f17ef44 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -2,16 +2,19 @@ # QAPI command marshaller generator # # Copyright IBM, Corp. 2011 +# Copyright (C) 2014 Red Hat, Inc. # # Authors: # Anthony Liguori # Michael Roth +# Markus Armbruster # # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. from ordereddict import OrderedDict from qapi import * +import re import sys import os import getopt @@ -37,6 +40,15 @@ def generate_command_decl(name, args, ret_type): ''', ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip() +def gen_err_check(errvar): + if errvar: + return mcgen(''' +if (local_err) { + goto out; +} +''') + return '' + def gen_sync_call(name, args, ret_type, indent=0): ret = "" arglist="" @@ -49,15 +61,14 @@ def gen_sync_call(name, args, ret_type, indent=0): arglist += "%s, " % (c_var(argname)) push_indent(indent) ret = mcgen(''' -%(retval)sqmp_%(name)s(%(args)serrp); +%(retval)sqmp_%(name)s(%(args)s&local_err); ''', name=c_fun(name), args=arglist, retval=retval).rstrip() if ret_type: + ret += "\n" + gen_err_check('local_err') ret += "\n" + mcgen('''' -if (!error_is_set(errp)) { - %(marshal_output_call)s -} +%(marshal_output_call)s ''', marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip() pop_indent(indent) @@ -67,7 +78,7 @@ if (!error_is_set(errp)) { def gen_marshal_output_call(name, ret_type): if not ret_type: return "" - return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name) + return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_fun(name) def gen_visitor_input_containers_decl(args, obj): ret = "" @@ -109,7 +120,8 @@ bool has_%(argname)s = false; def gen_visitor_input_block(args, dealloc=False): ret = "" - errparg = 'errp' + errparg = '&local_err' + errarg = 'local_err' if len(args) == 0: return ret @@ -118,6 +130,7 @@ def gen_visitor_input_block(args, dealloc=False): if dealloc: errparg = 'NULL' + errarg = None; ret += mcgen(''' qmp_input_visitor_cleanup(mi); md = qapi_dealloc_visitor_new(); @@ -132,15 +145,20 @@ v = qmp_input_get_visitor(mi); if optional: ret += mcgen(''' visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s); -if (has_%(c_name)s) { ''', c_name=c_var(argname), name=argname, errp=errparg) + ret += gen_err_check(errarg) + ret += mcgen(''' +if (has_%(c_name)s) { +''', + c_name=c_var(argname)) push_indent() ret += mcgen(''' %(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s); ''', c_name=c_var(argname), name=argname, argtype=argtype, visitor=type_visitor(argtype), errp=errparg) + ret += gen_err_check(errarg) if optional: pop_indent() ret += mcgen(''' @@ -161,15 +179,20 @@ def gen_marshal_output(name, args, ret_type, middle_mode): ret = mcgen(''' static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp) { + Error *local_err = NULL; QmpOutputVisitor *mo = qmp_output_visitor_new(); QapiDeallocVisitor *md; Visitor *v; v = qmp_output_get_visitor(mo); - %(visitor)s(v, &ret_in, "unused", errp); - if (!error_is_set(errp)) { - *ret_out = qmp_output_get_qobject(mo); + %(visitor)s(v, &ret_in, "unused", &local_err); + if (local_err) { + goto out; } + *ret_out = qmp_output_get_qobject(mo); + +out: + error_propagate(errp, local_err); qmp_output_visitor_cleanup(mo); md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); @@ -196,13 +219,12 @@ def gen_marshal_input(name, args, ret_type, middle_mode): ret = mcgen(''' %(header)s { + Error *local_err = NULL; ''', header=hdr) if middle_mode: ret += mcgen(''' - Error *local_err = NULL; - Error **errp = &local_err; QDict *args = (QDict *)qdict; ''') @@ -229,19 +251,22 @@ def gen_marshal_input(name, args, ret_type, middle_mode): visitor_input_block=gen_visitor_input_block(args)) else: ret += mcgen(''' + (void)args; ''') ret += mcgen(''' - if (error_is_set(errp)) { - goto out; - } %(sync_call)s ''', sync_call=gen_sync_call(name, args, ret_type, indent=4)) - ret += mcgen(''' + if re.search('^ *goto out\\;', ret, re.MULTILINE): + ret += mcgen(''' out: +''') + if not middle_mode: + ret += mcgen(''' + error_propagate(errp, local_err); ''') ret += mcgen(''' %(visitor_input_block_cleanup)s diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 1ef753a9b9..06a79f1631 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -2,16 +2,19 @@ # QAPI visitor generator # # Copyright IBM, Corp. 2011 +# Copyright (C) 2014 Red Hat, Inc. # # Authors: # Anthony Liguori # Michael Roth +# Markus Armbruster # # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. from ordereddict import OrderedDict from qapi import * +import re import sys import os import getopt @@ -32,9 +35,7 @@ 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); - error_propagate(errp, err); - err = NULL; + visit_type_%(c_type)s_fields(m, obj, errp); visit_end_implicit_struct(m, &err); } error_propagate(errp, err); @@ -64,12 +65,9 @@ def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj, Error **errp) { - Error *err = NULL; ''', name=name, full_name=full_name, c_name=c_var(argname)) - push_indent() ret += generate_visit_struct_body(full_name, argname, argentry) - pop_indent() ret += mcgen(''' } ''') @@ -89,6 +87,9 @@ static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s ** obj, Error * if base: ret += mcgen(''' visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err); +if (err) { + goto out; +} ''', c_prefix=c_var(field_prefix), type=type_name(base), c_name=c_var('base')) @@ -97,7 +98,7 @@ visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err); if optional: ret += mcgen(''' visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err); -if ((*obj)->%(prefix)shas_%(c_name)s) { +if (!err && (*obj)->%(prefix)shas_%(c_name)s) { ''', c_prefix=c_var(field_prefix), prefix=field_prefix, c_name=c_var(argname), name=argname) @@ -120,11 +121,20 @@ visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err); pop_indent() ret += mcgen(''' } +''') + ret += mcgen(''' +if (err) { + goto out; +} ''') pop_indent() - ret += mcgen(''' + if re.search('^ *goto out\\;', ret, re.MULTILINE): + ret += mcgen(''' +out: +''') + ret += mcgen(''' error_propagate(errp, err); } ''') @@ -133,9 +143,9 @@ visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err); def generate_visit_struct_body(field_prefix, name, members): ret = mcgen(''' -if (!error_is_set(errp)) { + Error *err = NULL; + ''') - push_indent() if not field_prefix: full_name = name @@ -144,36 +154,26 @@ if (!error_is_set(errp)) { if len(field_prefix): ret += mcgen(''' -visit_start_struct(m, NULL, "", "%(name)s", 0, &err); + visit_start_struct(m, NULL, "", "%(name)s", 0, &err); ''', name=name) else: ret += mcgen(''' -Error *err = NULL; -visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); + visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); ''', name=name) ret += mcgen(''' -if (!err) { - if (*obj) { - visit_type_%(name)s_fields(m, obj, &err); - error_propagate(errp, err); - err = NULL; + if (!err) { + if (*obj) { + visit_type_%(name)s_fields(m, obj, errp); + } + visit_end_struct(m, &err); } + error_propagate(errp, err); ''', name=full_name) - ret += mcgen(''' - /* Always call end_struct if start_struct succeeded. */ - visit_end_struct(m, &err); -} -error_propagate(errp, err); -''') - pop_indent() - ret += mcgen(''' -} -''') return ret def generate_visit_struct(expr): @@ -191,9 +191,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** ''', name=name) - push_indent() ret += generate_visit_struct_body("", name, members) - pop_indent() ret += mcgen(''' } @@ -205,24 +203,26 @@ def generate_visit_list(name, members): void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp) { - GenericList *i, **prev = (GenericList **)obj; Error *err = NULL; + GenericList *i, **prev; - if (!error_is_set(errp)) { - visit_start_list(m, name, &err); - if (!err) { - for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) { - %(name)sList *native_i = (%(name)sList *)i; - visit_type_%(name)s(m, &native_i->value, NULL, &err); - } - error_propagate(errp, err); - err = NULL; - - /* Always call end_list if start_list succeeded. */ - visit_end_list(m, &err); - } - error_propagate(errp, err); + visit_start_list(m, name, &err); + if (err) { + goto out; + } + + for (prev = (GenericList **)obj; + !err && (i = visit_next_list(m, prev, &err)) != NULL; + prev = &i) { + %(name)sList *native_i = (%(name)sList *)i; + visit_type_%(name)s(m, &native_i->value, NULL, &err); } + + error_propagate(errp, err); + err = NULL; + visit_end_list(m, &err); +out: + error_propagate(errp, err); } ''', name=name) @@ -244,10 +244,15 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** { Error *err = NULL; - if (!error_is_set(errp)) { - visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); - visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); - switch ((*obj)->kind) { + visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); + if (err) { + goto out; + } + visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); + if (err) { + goto out_end; + } + switch ((*obj)->kind) { ''', name=name) @@ -262,22 +267,24 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** enum_full_value = generate_enum_full_value(disc_type, key) ret += mcgen(''' - case %(enum_full_value)s: - visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); - break; + case %(enum_full_value)s: + visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); + break; ''', enum_full_value = enum_full_value, c_type = type_name(members[key]), c_name = c_fun(key)) ret += mcgen(''' - default: - abort(); - } - error_propagate(errp, err); - err = NULL; - visit_end_implicit_struct(m, &err); + default: + abort(); } +out_end: + error_propagate(errp, err); + err = NULL; + visit_end_implicit_struct(m, &err); +out: + error_propagate(errp, err); } ''') @@ -324,19 +331,20 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** { Error *err = NULL; - if (!error_is_set(errp)) { - visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); - if (!err) { - if (*obj) { + visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); + if (err) { + goto out; + } + if (*obj) { ''', name=name) - push_indent() - push_indent() - if base: ret += mcgen(''' visit_type_%(name)s_fields(m, obj, &err); + if (err) { + goto out_obj; + } ''', name=name) @@ -346,8 +354,10 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** disc_key = discriminator ret += mcgen(''' visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err); - if (!err) { - switch ((*obj)->kind) { + if (err) { + goto out_obj; + } + switch ((*obj)->kind) { ''', disc_type = disc_type, disc_key = disc_key) @@ -360,32 +370,25 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** enum_full_value = generate_enum_full_value(disc_type, key) ret += mcgen(''' - case %(enum_full_value)s: - ''' + fmt + ''' - break; + case %(enum_full_value)s: + ''' + fmt + ''' + break; ''', enum_full_value = enum_full_value, c_type=type_name(members[key]), c_name=c_fun(key)) ret += mcgen(''' - default: - abort(); - } + default: + abort(); } +out_obj: error_propagate(errp, err); err = NULL; -''') - pop_indent() - pop_indent() - - ret += mcgen(''' - } - /* Always call end_struct if start_struct succeeded. */ - visit_end_struct(m, &err); - } - error_propagate(errp, err); } + visit_end_struct(m, &err); +out: + error_propagate(errp, err); } ''') @@ -505,7 +508,7 @@ fdecl.write(mcgen(''' /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ /* - * schema-defined QAPI visitor function + * schema-defined QAPI visitor functions * * Copyright IBM, Corp. 2011 * diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c index ec798c2acf..0f770034b1 100644 --- a/tests/test-qmp-input-strict.c +++ b/tests/test-qmp-input-strict.c @@ -81,11 +81,19 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj, } visit_type_int(v, &(*obj)->integer, "integer", &err); + if (err) { + goto out_end; + } visit_type_bool(v, &(*obj)->boolean, "boolean", &err); + if (err) { + goto out_end; + } visit_type_str(v, &(*obj)->string, "string", &err); +out_end: + error_propagate(errp, err); + err = NULL; visit_end_struct(v, &err); - out: error_propagate(errp, err); } diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index a58a3e6fdb..1c8e87295c 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -199,16 +199,24 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj, visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), &err); - if (!err) { - visit_type_int(v, &(*obj)->integer, "integer", &err); - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - visit_type_str(v, &(*obj)->string, "string", &err); - - /* Always call end_struct if start_struct succeeded. */ - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); + if (err) { + goto out; } + visit_type_int(v, &(*obj)->integer, "integer", &err); + if (err) { + goto out_end; + } + visit_type_bool(v, &(*obj)->boolean, "boolean", &err); + if (err) { + goto out_end; + } + visit_type_str(v, &(*obj)->string, "string", &err); + +out_end: + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); +out: error_propagate(errp, err); } diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index dfd597cee1..9c154581d7 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -185,11 +185,19 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj, } visit_type_int(v, &(*obj)->integer, "integer", &err); + if (err) { + goto out_end; + } visit_type_bool(v, &(*obj)->boolean, "boolean", &err); + if (err) { + goto out_end; + } visit_type_str(v, &(*obj)->string, "string", &err); +out_end: + error_propagate(errp, err); + err = NULL; visit_end_struct(v, &err); - out: error_propagate(errp, err); } diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c index 85170e5c49..74d6481992 100644 --- a/tests/test-visitor-serialization.c +++ b/tests/test-visitor-serialization.c @@ -195,7 +195,7 @@ typedef struct TestStruct static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp) { - Error *err= NULL; + Error *err = NULL; visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), &err); if (err) { @@ -203,11 +203,19 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj, } visit_type_int(v, &(*obj)->integer, "integer", &err); + if (err) { + goto out_end; + } visit_type_bool(v, &(*obj)->boolean, "boolean", &err); + if (err) { + goto out_end; + } visit_type_str(v, &(*obj)->string, "string", &err); +out_end: + error_propagate(errp, err); + err = NULL; visit_end_struct(v, &err); - out: error_propagate(errp, err); } -- cgit v1.2.3-59-g8ed1b