mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 14:05:34 +00:00
qmp: Tighten output visitor rules
Tighten assertions in the QMP output visitor, so that: - qmp_output_get_qobject() can only be called after pairing a visit_end_* for every visit_start_* (rather than allowing it on a partially built object) - qmp_output_get_qobject() cannot be called unless at least one visit_type_* or visit_start/visit_end pair has occurred since creation/reset (the accidental return of NULL fixed by commit ab8bf1d7 would have been much easier to diagnose) - ensure that we are encountering the expected object or list type, to provide protection against mismatched push(struct)/ pop(list) or push(list)/pop(struct), similar to the qmp-input protection added in commit bdd8e6b5. - ensure that except for the root, 'name' is non-null inside a dict, and NULL inside a list (this may need changing later if we add "name.0" support for better error messages for a list, but for now it makes sure all users are at least consistent) Backports commit 56a6f02b8ce1fe41a2a9077593e46eca7d98267d from qemu
This commit is contained in:
parent
e5b2cff2bd
commit
ae8d475ae0
|
@ -83,9 +83,8 @@ static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
|
||||||
QObject *cur = e ? e->value : NULL;
|
QObject *cur = e ? e->value : NULL;
|
||||||
|
|
||||||
if (!cur) {
|
if (!cur) {
|
||||||
/* FIXME we should require the user to reset the visitor, rather
|
/* Don't allow reuse of visitor on more than one root */
|
||||||
* than throwing away the previous root */
|
assert(!qov->root);
|
||||||
qobject_decref(qov->root);
|
|
||||||
qov->root = value;
|
qov->root = value;
|
||||||
} else {
|
} else {
|
||||||
switch (qobject_type(cur)) {
|
switch (qobject_type(cur)) {
|
||||||
|
@ -94,6 +93,7 @@ static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
|
||||||
qdict_put_obj(qobject_to_qdict(cur), name, value);
|
qdict_put_obj(qobject_to_qdict(cur), name, value);
|
||||||
break;
|
break;
|
||||||
case QTYPE_QLIST:
|
case QTYPE_QLIST:
|
||||||
|
assert(!name);
|
||||||
qlist_append_obj(qobject_to_qlist(cur), value);
|
qlist_append_obj(qobject_to_qlist(cur), value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -115,7 +115,8 @@ static void qmp_output_start_struct(Visitor *v, const char *name, void **obj,
|
||||||
static void qmp_output_end_struct(Visitor *v, Error **errp)
|
static void qmp_output_end_struct(Visitor *v, Error **errp)
|
||||||
{
|
{
|
||||||
QmpOutputVisitor *qov = to_qov(v);
|
QmpOutputVisitor *qov = to_qov(v);
|
||||||
qmp_output_pop(qov);
|
QObject *value = qmp_output_pop(qov);
|
||||||
|
assert(qobject_type(value) == QTYPE_QDICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
|
static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
|
||||||
|
@ -146,7 +147,8 @@ static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
|
||||||
static void qmp_output_end_list(Visitor *v)
|
static void qmp_output_end_list(Visitor *v)
|
||||||
{
|
{
|
||||||
QmpOutputVisitor *qov = to_qov(v);
|
QmpOutputVisitor *qov = to_qov(v);
|
||||||
qmp_output_pop(qov);
|
QObject *value = qmp_output_pop(qov);
|
||||||
|
assert(qobject_type(value) == QTYPE_QLIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj,
|
static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj,
|
||||||
|
@ -203,18 +205,16 @@ static void qmp_output_type_null(Visitor *v, const char *name, Error **errp)
|
||||||
qmp_output_add_obj(qov, name, qnull());
|
qmp_output_add_obj(qov, name, qnull());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finish building, and return the root object. Will not be NULL. */
|
/* Finish building, and return the root object.
|
||||||
|
* The root object is never null. The caller becomes the object's
|
||||||
|
* owner, and should use qobject_decref() when done with it. */
|
||||||
QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
|
QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
|
||||||
{
|
{
|
||||||
/* FIXME: we should require that a visit occurred, and that it is
|
/* A visit must have occurred, with each start paired with end. */
|
||||||
* complete (no starts without a matching end) */
|
assert(qov->root && QTAILQ_EMPTY(&qov->stack));
|
||||||
QObject *obj = qov->root;
|
|
||||||
if (obj) {
|
qobject_incref(qov->root);
|
||||||
qobject_incref(obj);
|
return qov->root;
|
||||||
} else {
|
|
||||||
obj = qnull();
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
|
Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
|
||||||
|
|
Loading…
Reference in a new issue