From 0b9d15dd526f36458263f340c340cd6ca532cd35 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 19 Feb 2018 14:06:22 -0500 Subject: [PATCH] qapi: Whitelist commands that don't return dictionary ...or an array of dictionaries. Although we have to cater to existing commands, returning a non-dictionary means the command is not extensible (no new name/value pairs can be added if more information must be returned in parallel). By making the whitelist explicit, any new command that falls foul of this practice will have to be self-documenting, which will encourage developers to either justify the action or rework the design to use a dictionary after all. It's a little bit sloppy that we share a single whitelist among three clients (it's too permissive for each). If this is a problem, a future patch could tighten things by having the generator take the whitelist as an argument (as in scripts/qapi-commands.py --legacy-returns=...), or by having the generator output C code that requires explicit use of the whitelist (as in: then having the callers define appropriate macros). But until we need such fine-grained separation (if ever), this patch does the job just fine. Backports commit 10d4d997f86cf2a4ce89145df5658952d5722e56 from qemu --- qemu/scripts/qapi.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/qemu/scripts/qapi.py b/qemu/scripts/qapi.py index 6edde2c8..bcf894b1 100644 --- a/qemu/scripts/qapi.py +++ b/qemu/scripts/qapi.py @@ -32,6 +32,30 @@ builtin_types = { 'size': 'QTYPE_QINT', } +# Whitelist of commands allowed to return a non-dictionary +returns_whitelist = [ + # From QMP: + 'human-monitor-command', + 'query-migrate-cache-size', + 'query-tpm-models', + 'query-tpm-types', + 'ringbuf-read', + + # From QGA: + 'guest-file-open', + 'guest-fsfreeze-freeze', + 'guest-fsfreeze-freeze-list', + 'guest-fsfreeze-status', + 'guest-fsfreeze-thaw', + 'guest-get-time', + 'guest-set-vcpus', + 'guest-sync', + 'guest-sync-delimited', + + # From qapi-schema-test: + 'user_def_cmd3', +] + enum_types = [] struct_types = [] union_types = [] @@ -354,11 +378,12 @@ def check_command(expr, expr_info): check_type(expr_info, "'data' for command '%s'" % name, expr.get('data'), allow_dict=True, allow_optional=True, allow_metas=['union', 'struct']) + returns_meta = ['union', 'struct'] + if name in returns_whitelist: + returns_meta += ['built-in', 'alternate', 'enum'] check_type(expr_info, "'returns' for command '%s'" % name, expr.get('returns'), allow_array=True, allow_dict=True, - allow_optional=True, - allow_metas=['built-in', 'union', 'alternate', 'struct', - 'enum']) + allow_optional=True, allow_metas=returns_meta) def check_event(expr, expr_info): global events