qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v3 09/14] qapi: add check_type helper function


From: Markus Armbruster
Subject: Re: [Qemu-devel] [PATCH v3 09/14] qapi: add check_type helper function
Date: Thu, 14 Aug 2014 18:10:11 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux)

Eric Blake <address@hidden> writes:

> On 08/14/2014 04:10 AM, Markus Armbruster wrote:
>> Subject suggests you're merely adding a helper function.  You're
>> actually fixing bugs.  Something like
>> 
>>     qapi: More rigorous checking of type expressions
>> 
>> would be clearer.
>
> Along with squashing in 8/14, you are correct about this fixing bugs
> (serves me right for refactoring, then realizing that we needed more
> tests, then fixing the tests without checking that the subject line
> stayed appropriate).
>
>>> +++ b/scripts/qapi.py
>>> @@ -329,6 +329,32 @@ def check_union(expr, expr_info):
>>>          # Todo: add checking for values. Key is checked as above,
>>> value can be
>>>          # also checked here, but we need more functions to handle
>>> array case.
>>>
>>> +def check_type(expr_info, name, data, allow_native = False):
>>> +    if not data:
>>> +        return
>>> +    if isinstance(data, list):
>>> +        if len(data) != 1 or not isinstance(data[0], basestring):
>>> +            raise QAPIExprError(expr_info,
>>> +                                "Use of array type in '%s' must contain "
>>> +                                "single element type name" % name)
>>> +        data = data[0]
>> 
>> Peeling off the array here means error messages below won't mention it.
>> Visible in data-array-unknown.err below.  But good enough is good
>> enough.
>> 
>>> +
>>> +    if isinstance(data, basestring):
>>> +        if find_struct(data) or find_enum(data) or find_union(data):
>>> +            return
>>> +        if data == 'str' or data == 'int' or data == 'visitor':
>> 
>> Is this complete?  Should we be checking against builtin_types[]?
>
> It was complete insofar that it passes with the current
> qapi-schema.json.  Checking builtin_types[] would indeed be nicer (I
> didn't know that existed).
>
>> 
>> Pardon my ignorance: where does 'visitor' come from?
>
> qom-set, qom-get.  Nasty commands that aren't typesafe, and which
> explicitly use 'gen':'no' to abuse the qapi system by bypassing the code
> generator while still exposing a backdoor command that can break the rules.
>
> netdev_add ('*props':'**') and object-add ('*props':'dict') are the only
> other 'gen':'no' clients; I'm not sure why they didn't cause the parser
> to barf the way 'visitor' did.  Maybe my approach should instead be to
> unify all four 'gen':'no' expressions to use the same syntax of "**" to
> represent the fact that the QMP code is not type-safe, as well as
> actually documenting this (ab)use of ** (the fact that none of the
> documentation mentions 'gen' is telling).  Looks like I've just added a
> pre-req patch into my v4 :)

Documentation for 'gen': 'no', '**', and 'visitor' is most welcome.

I wonder why 'no', and not simply false.  Hmm, looks like the code
generator ignores the value.  'gen': 'sure, why not, if you feel like
it'.

Should 'visitor' be in builtin_types[]?

>>> +            if allow_native:
>>> +                return
>>> +            raise QAPIExprError(expr_info,
>>> +                                "Primitive type '%s' not allowed as data "
>>> +                                "of '%s'" % (data, name))
>>> +        raise QAPIExprError(expr_info,
>>> +                            "Unknown type '%s' as data of '%s'"
>>> +                            % (data, name))
>> 
>> "as data of" suggests the problem is in member 'data', even when it's
>> actually in member 'returns'.  Visible in returns-unknown.err below.
>
> The function is declared as:
>
>>> +def check_type(expr_info, name, data, allow_native = False):
>
> but allow_native is True only for the 'returns' case.  Maybe I should
> just repurpose that parameter for what it really is - 'data' vs.
> 'returns', and use it for improving the error message in addition to
> deciding whether native types are allowed.

Yeah.

>>> +    elif not isinstance(data, OrderedDict):
>>> +        raise QAPIExprError(expr_info,
>>> +                            "Expecting dictionary for data of '%s'" % name)
>>> +
>>>  def check_exprs(schema):
>>>      for expr_elem in schema.exprs:
>>>          expr = expr_elem['expr']
>>> @@ -356,6 +382,10 @@ def check_exprs(schema):
>>>                  raise QAPIExprError(info,
>>>                                      "enum '%s' requires an array for 
>>> 'data'"
>>>                                      % expr.get('enum'))
>>> +        else:
>> 
>> This is for 'type' and 'command', right?
>
> 'type', 'union', 'event', and 'command' ('data' is a dict for those
> four, and an array for the fifth meta-type of 'enum').  I'll add a comment.

You're right.  I misread the sequence of if statements as one big
if... elif... elif... else statement.

A blank line before the if... else would probably do.

>> 
>>> +            check_type(info, expr_name(expr), members)
>>> +            if expr.has_key('command') and expr.has_key('returns'):
>>> +                check_type(info, expr['command'], expr['returns'], True)
>>>
>>>  def parse_schema(input_file):
>>>      try:
>> 
>> Looks pretty good, but I didn't check systematically against
>> qapi-code-gen.txt for correctness and completeness.  We can always
>> improve on top.
>
> I'll double-check things as well, when posting v4.

Thanks!



reply via email to

[Prev in Thread] Current Thread [Next in Thread]