diff --git a/msvc/unicorn/qapi-visit.c b/msvc/unicorn/qapi-visit.c index fa09fdab..dc2bf133 100644 --- a/msvc/unicorn/qapi-visit.c +++ b/msvc/unicorn/qapi-visit.c @@ -47,7 +47,7 @@ void visit_type_DummyForceArrays(Visitor *v, const char *name, DummyForceArrays } visit_check_struct(v, &err); out_obj: - visit_end_struct(v); + visit_end_struct(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_DummyForceArrays(*obj); *obj = NULL; @@ -114,7 +114,7 @@ void visit_type_X86CPUFeatureWordInfo(Visitor *v, const char *name, X86CPUFeatur } visit_check_struct(v, &err); out_obj: - visit_end_struct(v); + visit_end_struct(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_X86CPUFeatureWordInfo(*obj); *obj = NULL; @@ -144,7 +144,7 @@ void visit_type_X86CPUFeatureWordInfoList(Visitor *v, const char *name, X86CPUFe error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_X86CPUFeatureWordInfoList(*obj); *obj = NULL; @@ -181,7 +181,7 @@ void visit_type_anyList(Visitor *v, const char *name, anyList **obj, Error **err error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_anyList(*obj); *obj = NULL; @@ -211,7 +211,7 @@ void visit_type_boolList(Visitor *v, const char *name, boolList **obj, Error **e error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_boolList(*obj); *obj = NULL; @@ -241,7 +241,7 @@ void visit_type_int16List(Visitor *v, const char *name, int16List **obj, Error * error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_int16List(*obj); *obj = NULL; @@ -271,7 +271,7 @@ void visit_type_int32List(Visitor *v, const char *name, int32List **obj, Error * error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_int32List(*obj); *obj = NULL; @@ -301,7 +301,7 @@ void visit_type_int64List(Visitor *v, const char *name, int64List **obj, Error * error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_int64List(*obj); *obj = NULL; @@ -331,7 +331,7 @@ void visit_type_int8List(Visitor *v, const char *name, int8List **obj, Error **e error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_int8List(*obj); *obj = NULL; @@ -361,7 +361,7 @@ void visit_type_intList(Visitor *v, const char *name, intList **obj, Error **err error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_intList(*obj); *obj = NULL; @@ -391,7 +391,7 @@ void visit_type_numberList(Visitor *v, const char *name, numberList **obj, Error error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_numberList(*obj); *obj = NULL; @@ -421,7 +421,7 @@ void visit_type_sizeList(Visitor *v, const char *name, sizeList **obj, Error **e error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_sizeList(*obj); *obj = NULL; @@ -451,7 +451,7 @@ void visit_type_strList(Visitor *v, const char *name, strList **obj, Error **err error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_strList(*obj); *obj = NULL; @@ -481,7 +481,7 @@ void visit_type_uint16List(Visitor *v, const char *name, uint16List **obj, Error error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_uint16List(*obj); *obj = NULL; @@ -511,7 +511,7 @@ void visit_type_uint32List(Visitor *v, const char *name, uint32List **obj, Error error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_uint32List(*obj); *obj = NULL; @@ -541,7 +541,7 @@ void visit_type_uint64List(Visitor *v, const char *name, uint64List **obj, Error error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_uint64List(*obj); *obj = NULL; @@ -571,7 +571,7 @@ void visit_type_uint8List(Visitor *v, const char *name, uint8List **obj, Error * error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_uint8List(*obj); *obj = NULL; diff --git a/qemu/include/qapi/visitor-impl.h b/qemu/include/qapi/visitor-impl.h index d140fb20..2e185b84 100644 --- a/qemu/include/qapi/visitor-impl.h +++ b/qemu/include/qapi/visitor-impl.h @@ -48,7 +48,7 @@ struct Visitor void (*check_struct)(Visitor *v, Error **errp); /* Must be set to visit structs */ - void (*end_struct)(Visitor *v); + void (*end_struct)(Visitor *v, void **obj); /* Must be set; implementations may require @list to be non-null, * but must document it. */ @@ -59,7 +59,7 @@ struct Visitor GenericList *(*next_list)(Visitor *v, GenericList *tail, size_t size); /* Must be set */ - void (*end_list)(Visitor *v); + void (*end_list)(Visitor *v, void **list); /* Must be set by input and dealloc visitors to visit alternates; * optional for output visitors. */ @@ -68,7 +68,7 @@ struct Visitor bool promote_int, Error **errp); /* Optional, needed for dealloc visitor */ - void (*end_alternate)(Visitor *v); + void (*end_alternate)(Visitor *v, void **obj); /* Must be set */ void (*type_int64)(Visitor *v, const char *name, int64_t *obj, diff --git a/qemu/include/qapi/visitor.h b/qemu/include/qapi/visitor.h index 304f476f..564f4063 100644 --- a/qemu/include/qapi/visitor.h +++ b/qemu/include/qapi/visitor.h @@ -195,12 +195,12 @@ * goto outlist; * } * outlist: - * visit_end_list(v); + * visit_end_list(v, NULL); * if (!err) { * visit_check_struct(v, &err); * } * outobj: - * visit_end_struct(v); + * visit_end_struct(v, NULL); * out: * error_propagate(errp, err); * ...clean up v... @@ -246,8 +246,8 @@ typedef struct GenericAlternate { * After visit_start_struct() succeeds, the caller may visit its * members one after the other, passing the member's name and address * within the struct. Finally, visit_end_struct() needs to be called - * to clean up, even if intermediate visits fail. See the examples - * above. + * with the same @obj to clean up, even if intermediate visits fail. + * See the examples above. * * FIXME Should this be named visit_start_object, since it is also * used for QAPI unions, and maps to JSON objects? @@ -271,12 +271,14 @@ void visit_check_struct(Visitor *v, Error **errp); /* * Complete an object visit started earlier. * + * @obj must match what was passed to the paired visit_start_struct(). + * * Must be called after any successful use of visit_start_struct(), * even if intermediate processing was skipped due to errors, to allow * the backend to release any resources. Destroying the visitor early * behaves as if this was implicitly called. */ -void visit_end_struct(Visitor *v); +void visit_end_struct(Visitor *v, void **obj); /*** Visiting lists ***/ @@ -303,8 +305,9 @@ void visit_end_struct(Visitor *v); * visit (where @obj is NULL) uses other means. For each list * element, call the appropriate visit_type_FOO() with name set to * NULL and obj set to the address of the value member of the list - * element. Finally, visit_end_list() needs to be called to clean up, - * even if intermediate visits fail. See the examples above. + * element. Finally, visit_end_list() needs to be called with the + * same @list to clean up, even if intermediate visits fail. See the + * examples above. */ void visit_start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp); @@ -333,12 +336,14 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size); /* * Complete a list visit started earlier. * + * @list must match what was passed to the paired visit_start_list(). + * * Must be called after any successful use of visit_start_list(), even * if intermediate processing was skipped due to errors, to allow the * backend to release any resources. Destroying the visitor early * behaves as if this was implicitly called. */ -void visit_end_list(Visitor *v); +void visit_end_list(Visitor *v, void **list); /* * Start the visit of an alternate @obj. @@ -353,8 +358,9 @@ void visit_end_list(Visitor *v); * * If @promote_int, treat integers as QTYPE_FLOAT. * - * If successful, this must be paired with visit_end_alternate() to - * clean up, even if visiting the contents of the alternate fails. + * If successful, this must be paired with visit_end_alternate() with + * the same @obj to clean up, even if visiting the contents of the + * alternate fails. */ void visit_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, @@ -363,15 +369,14 @@ void visit_start_alternate(Visitor *v, const char *name, /* * Finish visiting an alternate type. * + * @obj must match what was passed to the paired visit_start_alternate(). + * * Must be called after any successful use of visit_start_alternate(), * even if intermediate processing was skipped due to errors, to allow * the backend to release any resources. Destroying the visitor early * behaves as if this was implicitly called. - * - * 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); +void visit_end_alternate(Visitor *v, void **obj); /*** Other helpers ***/ diff --git a/qemu/qapi/qapi-dealloc-visitor.c b/qemu/qapi/qapi-dealloc-visitor.c index 06c2d25a..ba0ee854 100644 --- a/qemu/qapi/qapi-dealloc-visitor.c +++ b/qemu/qapi/qapi-dealloc-visitor.c @@ -19,54 +19,19 @@ #include "qapi/qmp/types.h" #include "qapi/visitor-impl.h" -typedef struct StackEntry -{ - void *value; - QTAILQ_ENTRY(StackEntry) node; -} StackEntry; - struct QapiDeallocVisitor { Visitor visitor; - QTAILQ_HEAD(, StackEntry) stack; bool is_list_head; }; -static QapiDeallocVisitor *to_qov(Visitor *v) -{ - return container_of(v, QapiDeallocVisitor, visitor); -} - -static void qapi_dealloc_push(QapiDeallocVisitor *qov, void *value) -{ - StackEntry *e = g_malloc0(sizeof(*e)); - - e->value = value; - - QTAILQ_INSERT_HEAD(&qov->stack, e, node); -} - -static void *qapi_dealloc_pop(QapiDeallocVisitor *qov) -{ - StackEntry *e = QTAILQ_FIRST(&qov->stack); - QObject *value; - QTAILQ_REMOVE(&qov->stack, e, node); - value = e->value; - g_free(e); - return value; -} - static void qapi_dealloc_start_struct(Visitor *v, const char *name, void **obj, size_t unused, Error **errp) { - QapiDeallocVisitor *qov = to_qov(v); - qapi_dealloc_push(qov, obj); } -static void qapi_dealloc_end_struct(Visitor *v) +static void qapi_dealloc_end_struct(Visitor *v, void **obj) { - QapiDeallocVisitor *qov = to_qov(v); - void **obj = qapi_dealloc_pop(qov); if (obj) { g_free(*obj); } @@ -76,14 +41,10 @@ static void qapi_dealloc_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, bool promote_int, Error **errp) { - QapiDeallocVisitor *qov = to_qov(v); - qapi_dealloc_push(qov, obj); } -static void qapi_dealloc_end_alternate(Visitor *v) +static void qapi_dealloc_end_alternate(Visitor *v, void **obj) { - QapiDeallocVisitor *qov = to_qov(v); - void **obj = qapi_dealloc_pop(qov); if (obj) { g_free(*obj); } @@ -103,7 +64,7 @@ static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList *tail, return next; } -static void qapi_dealloc_end_list(Visitor *v) +static void qapi_dealloc_end_list(Visitor *v, void **obj) { } @@ -185,7 +146,5 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void) v->visitor.type_null = qapi_dealloc_type_null; v->visitor.type_size = qapi_dealloc_type_size; - QTAILQ_INIT(&v->stack); - return v; } diff --git a/qemu/qapi/qapi-visit-core.c b/qemu/qapi/qapi-visit-core.c index a7025872..2728b910 100644 --- a/qemu/qapi/qapi-visit-core.c +++ b/qemu/qapi/qapi-visit-core.c @@ -44,9 +44,9 @@ void visit_check_struct(Visitor *v, Error **errp) } } -void visit_end_struct(Visitor *v) +void visit_end_struct(Visitor *v, void **obj) { - v->end_struct(v); + v->end_struct(v, obj); } void visit_start_list(Visitor *v, const char *name, GenericList **list, @@ -68,9 +68,9 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) return v->next_list(v, tail, size); } -void visit_end_list(Visitor *v) +void visit_end_list(Visitor *v, void **obj) { - v->end_list(v); + v->end_list(v, obj); } void visit_start_alternate(Visitor *v, const char *name, @@ -84,10 +84,10 @@ void visit_start_alternate(Visitor *v, const char *name, } } -void visit_end_alternate(Visitor *v) +void visit_end_alternate(Visitor *v, void **obj) { if (v->end_alternate) { - v->end_alternate(v); + v->end_alternate(v, obj); } } diff --git a/qemu/qapi/qmp-input-visitor.c b/qemu/qapi/qmp-input-visitor.c index 0be7798b..67a44aa0 100644 --- a/qemu/qapi/qmp-input-visitor.c +++ b/qemu/qapi/qmp-input-visitor.c @@ -25,6 +25,7 @@ typedef struct StackObject { QObject *obj; /* Object being visited */ + void *qapi; /* sanity check that caller uses same pointer */ GHashTable *h; /* If obj is dict: unvisited keys */ const QListEntry *entry; /* If obj is list: unvisited tail */ @@ -95,7 +96,7 @@ static void qdict_add_key(const char *key, QObject *obj, void *opaque) } static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj, - Error **errp) + void *qapi, Error **errp) { GHashTable *h; StackObject *tos = &qiv->stack[qiv->nb_stack]; @@ -107,6 +108,7 @@ static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj, } tos->obj = obj; + tos->qapi = qapi; assert(!tos->h); assert(!tos->entry); @@ -148,12 +150,13 @@ static void qmp_input_check_struct(Visitor *v, Error **errp) } } -static void qmp_input_pop(Visitor *v) +static void qmp_input_pop(Visitor *v, void **obj) { QmpInputVisitor *qiv = to_qiv(v); StackObject *tos = &qiv->stack[qiv->nb_stack - 1]; assert(qiv->nb_stack > 0); + assert(tos->qapi == obj); if (qiv->strict) { GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h; @@ -182,7 +185,7 @@ static void qmp_input_start_struct(Visitor *v, const char *name, void **obj, return; } - qmp_input_push(qiv, qobj, &err); + qmp_input_push(qiv, qobj, obj, &err); if (err) { error_propagate(errp, err); return; @@ -209,7 +212,7 @@ static void qmp_input_start_list(Visitor *v, const char *name, return; } - entry = qmp_input_push(qiv, qobj, errp); + entry = qmp_input_push(qiv, qobj, list, errp); if (list) { if (entry) { *list = g_malloc0(size); diff --git a/qemu/qapi/qmp-output-visitor.c b/qemu/qapi/qmp-output-visitor.c index 0e9992ad..76d76a0a 100644 --- a/qemu/qapi/qmp-output-visitor.c +++ b/qemu/qapi/qmp-output-visitor.c @@ -23,6 +23,7 @@ typedef struct QStackEntry { QObject *value; + void *qapi; /* sanity check that caller uses same pointer */ QTAILQ_ENTRY(QStackEntry) node; } QStackEntry; @@ -37,7 +38,8 @@ struct QmpOutputVisitor #define qmp_output_add(qov, name, value) \ qmp_output_add_obj(qov, name, QOBJECT(value)) -#define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value)) +#define qmp_output_push(qov, value, qapi) \ + qmp_output_push_obj(qov, QOBJECT(value), qapi) static QmpOutputVisitor *to_qov(Visitor *v) { @@ -45,23 +47,26 @@ static QmpOutputVisitor *to_qov(Visitor *v) } /* Push @value onto the stack of current QObjects being built */ -static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value) +static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value, + void *qapi) { QStackEntry *e = g_malloc0(sizeof(*e)); assert(qov->root); assert(value); e->value = value; + e->qapi = qapi; QTAILQ_INSERT_HEAD(&qov->stack, e, node); } /* Pop a value off the stack of QObjects being built, and return it. */ -static QObject *qmp_output_pop(QmpOutputVisitor *qov) +static QObject *qmp_output_pop(QmpOutputVisitor *qov, void *qapi) { QStackEntry *e = QTAILQ_FIRST(&qov->stack); QObject *value; assert(e); + assert(e->qapi == qapi); QTAILQ_REMOVE(&qov->stack, e, node); value = e->value; assert(value); @@ -105,13 +110,13 @@ static void qmp_output_start_struct(Visitor *v, const char *name, void **obj, QDict *dict = qdict_new(); qmp_output_add(qov, name, dict); - qmp_output_push(qov, dict); + qmp_output_push(qov, dict, obj); } -static void qmp_output_end_struct(Visitor *v) +static void qmp_output_end_struct(Visitor *v, void **obj) { QmpOutputVisitor *qov = to_qov(v); - QObject *value = qmp_output_pop(qov); + QObject *value = qmp_output_pop(qov, obj); assert(qobject_type(value) == QTYPE_QDICT); } @@ -123,7 +128,7 @@ static void qmp_output_start_list(Visitor *v, const char *name, QList *list = qlist_new(); qmp_output_add(qov, name, list); - qmp_output_push(qov, list); + qmp_output_push(qov, list, listp); } static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail, @@ -132,10 +137,10 @@ static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail, return tail->next; } -static void qmp_output_end_list(Visitor *v) +static void qmp_output_end_list(Visitor *v, void **obj) { QmpOutputVisitor *qov = to_qov(v); - QObject *value = qmp_output_pop(qov); + QObject *value = qmp_output_pop(qov, obj); assert(qobject_type(value) == QTYPE_QLIST); } diff --git a/qemu/qapi/string-input-visitor.c b/qemu/qapi/string-input-visitor.c index dd132459..fb514970 100644 --- a/qemu/qapi/string-input-visitor.c +++ b/qemu/qapi/string-input-visitor.c @@ -30,6 +30,7 @@ struct StringInputVisitor int64_t cur; const char *string; + void *list; /* Only needed for sanity checking the caller */ }; static StringInputVisitor *to_siv(Visitor *v) @@ -120,6 +121,7 @@ start_list(Visitor *v, const char *name, GenericList **list, size_t size, /* We don't support visits without a list */ assert(list); + siv->list = list; if (parse_str(siv, name, errp) < 0) { *list = NULL; @@ -168,8 +170,11 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size) return tail->next; } -static void end_list(Visitor *v) +static void end_list(Visitor *v, void **obj) { + StringInputVisitor *siv = to_siv(v); + + assert(siv->list == obj); } static void parse_type_int64(Visitor *v, const char *name, int64_t *obj, diff --git a/qemu/scripts/qapi-event.py b/qemu/scripts/qapi-event.py index 69ccee1d..64db422a 100644 --- a/qemu/scripts/qapi-event.py +++ b/qemu/scripts/qapi-event.py @@ -101,7 +101,7 @@ def gen_event_send(name, arg_type): if (!err) { visit_check_struct(v, &err); } - visit_end_struct(v); + visit_end_struct(v, NULL); if (err) { goto out; } diff --git a/qemu/scripts/qapi-visit.py b/qemu/scripts/qapi-visit.py index a1050651..877ace16 100644 --- a/qemu/scripts/qapi-visit.py +++ b/qemu/scripts/qapi-visit.py @@ -129,7 +129,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error error_propagate(errp, err); err = NULL; - visit_end_list(v); + visit_end_list(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_%(c_name)s(*obj); *obj = NULL; @@ -194,7 +194,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error if (!err) { visit_check_struct(v, &err); } - visit_end_struct(v); + visit_end_struct(v, NULL); ''', c_type=var.type.c_name(), c_name=c_name(var.name)) @@ -216,7 +216,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error "%(name)s"); } out_obj: - visit_end_alternate(v); + visit_end_alternate(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_%(c_name)s(*obj); *obj = NULL; @@ -250,7 +250,7 @@ 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); + visit_end_struct(v, (void **)obj); if (err && visit_is_input(v)) { qapi_free_%(c_name)s(*obj); *obj = NULL;