Eric Blake <ebl...@redhat.com> writes: > The qmp-input visitor was playing rather fast and loose: when
I guess (some of) its *users* are playing fast and loose, and the visitor itself lets them. The patch's title suggests "some of its users" == qapi-commands.py. > visiting a QDict, you could grab members of the root dictionary > without first pushing into the dict. But we are about to tighten > the input visitor, at which point the generated marshal code > MUST follow the same paradigms as everyone else, of pushing into > the struct before grabbing its keys, because the value of 'name' > should be ignored on the top-level visit. > > Generated code grows as follows: > > |@@ -515,7 +695,15 @@ void qmp_marshal_blockdev_backup(QDict * > | BlockdevBackup arg = {0}; > | > | v = qmp_input_get_visitor(qiv); > |+ visit_start_struct(v, NULL, NULL, 0, &err); > |+ if (err) { > |+ goto out; > |+ } > | visit_type_BlockdevBackup_members(v, &arg, &err); > |+ if (!err) { > |+ visit_check_struct(v, &err); > |+ } Does this find errors that weren't found before? > |+ visit_end_struct(v); > | if (err) { > | goto out; > | } > |@@ -527,7 +715,9 @@ out: > | qmp_input_visitor_cleanup(qiv); > | qdv = qapi_dealloc_visitor_new(); > | v = qapi_dealloc_get_visitor(qdv); > |+ visit_start_struct(v, NULL, NULL, 0, NULL); > | visit_type_BlockdevBackup_members(v, &arg, NULL); > |+ visit_end_struct(v); > | qapi_dealloc_visitor_cleanup(qdv); > | } > > Note that this change could also make it possible for the > marshalling code to automatically detect excess input at the top > level, and not just in nested dictionaries. However, that checking > is not currently useful (and we rely on the manual checking in > monitor.c:qmp_check_client_args() instead) as long as qmp-commands.hx > uses .args_type, and as long as we have 'name:O' as an arg-type that > explicitly allows unknown top-level keys because we haven't yet > converted 'device_add' and 'netdev_add' to introspectible use of > 'any'. Hmm, that explains why finding these additional errors wouldn't be useful. Good to know, but doesn't quite answer my question. > Signed-off-by: Eric Blake <ebl...@redhat.com> > > --- > v14: rebase to master context > v13: rebase to earlier patches > v12: new patch > --- > scripts/qapi-commands.py | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py > index b570069..9c1bd25 100644 > --- a/scripts/qapi-commands.py > +++ b/scripts/qapi-commands.py > @@ -121,7 +121,15 @@ def gen_marshal(name, arg_type, ret_type): > %(c_name)s arg = {0}; > > v = qmp_input_get_visitor(qiv); > + visit_start_struct(v, NULL, NULL, 0, &err); > + if (err) { > + goto out; > + } > visit_type_%(c_name)s_members(v, &arg, &err); > + if (!err) { > + visit_check_struct(v, &err); > + } > + visit_end_struct(v); > if (err) { > goto out; > } > @@ -150,7 +158,9 @@ out: > qmp_input_visitor_cleanup(qiv); > qdv = qapi_dealloc_visitor_new(); > v = qapi_dealloc_get_visitor(qdv); > + visit_start_struct(v, NULL, NULL, 0, NULL); > visit_type_%(c_name)s_members(v, &arg, NULL); > + visit_end_struct(v); > qapi_dealloc_visitor_cleanup(qdv); > ''', > c_name=arg_type.c_name()) No visit_check_struct() here. I think its contract should explicitly state that you may omit it when you're not interested in errors.