[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 10/10] qapi: Clean up null checking in generated
From: |
Markus Armbruster |
Subject: |
Re: [Qemu-devel] [PATCH 10/10] qapi: Clean up null checking in generated visitors |
Date: |
Mon, 10 Feb 2014 14:29:14 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.2 (gnu/linux) |
Markus Armbruster <address@hidden> writes:
> Paolo Bonzini <address@hidden> writes:
>
>> Il 06/02/2014 15:30, Markus Armbruster ha scritto:
>>> Visitors get passed a pointer to the visited object. The generated
>>> visitors try to cope with this pointer being null in some places, for
>>> instance like this:
>>>
>>> visit_start_optional(m, obj ? &(*obj)->has_name : NULL, "name", &err);
>>>
>>> visit_start_optional() passes its second argument to Visitor method
>>> start_optional. Two out of two methods dereference it
>>> unconditionally.
>>
>> Some visitor implementations however do not implement start_optional
>> at all. With these visitor implementations, you currently could pass
>> a NULL object. After your patch, you still can but you're passing a
>> bad pointer which is also a problem (perhaps one that Coverity would
>> also detect).
>
> We need to decide what the contract for the public visit_type_FOO() and
> visit_type_FOOlist() is.
>
> No existing user wants to pass a null pointer, the semantics of passing
> a null pointer are not obvious to me, and as we'll see below, the
> generated code isn't entirely successful in avoiding to dereference a
> null argument :)
>
>>> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
>>> index ff4239c..3eb10c8 100644
>>> --- a/scripts/qapi-visit.py
>>> +++ b/scripts/qapi-visit.py
>>> @@ -47,9 +47,9 @@ static void visit_type_%(full_name)s_fields(Visitor *m,
>>> %(name)s ** obj, Error *
>>>
>>> if base:
>>> ret += mcgen('''
>>> -visit_start_implicit_struct(m, obj ? (void**) &(*obj)->%(c_name)s : NULL,
>>> sizeof(%(type)s), &err);
>>> +visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s,
>>> sizeof(%(type)s), &err);
>>
>> This is the implementation of start_implicit_struct:
>
> One of two implementations.
>
>> static void qmp_input_start_implicit_struct(Visitor *v, void **obj,
>> size_t size, Error **errp)
>> {
>> if (obj) {
>> *obj = g_malloc0(size);
>> }
>> }
>>
>> Before your patch, if obj is NULL, *obj is not written.
>>
>> After your patch, if obj is NULL, and c_name is not the first field in
>> the struct, *obj is written and you get a NULL pointer
>> dereference. Same for end_implicit_struct in
>> qapi/qapi-dealloc-visitor.c.
>>
>> So I think if you remove this checking, you need to do the same in the
>> visitor implementations as well.
>
> Can do.
I'd like to keep this null check. Let me explain why.
The start_struct() callback gets called in two separate ways.
1. Boxed struct: argument is a struct **.
2. Unboxed struct: argument is null.
Example: UserDefTwo from tests/qapi-schema/qapi-schema-test.json
Schema:
{ 'type': 'UserDefTwo',
'data': { 'string': 'str',
'dict': { 'string': 'str',
... } } }
Generated type:
struct UserDefTwo
{
char * string;
struct
{
char * string;
...
} dict;
};
The generated visit_type_UserDefTwo() takes a struct UserDefOne **
argument, which can't sensibly be null, as discussed earlier in this
thread.
It passes that argument to visit_start_struct(). This is the boxed
case.
When it's time to visit UserDefTwo member dict, it calls
visit_start_struct() again, but with a null argument. This is the
unboxed case.
Therefore, implementations of start_struct() better be prepared for a
null argument. opts_start_struct() isn't, and I'm going to fix it.
start_implicit_struct() is not currently called with a null argument as
far as I can tell, but I'd prefer to keep it close to start_struct().
The fact that we're still committing interfaces like
include/qapi/visitor.h without spelling out at least the non-obvious
parts of the callback contracts is depressing.
[...]
- [Qemu-devel] [PATCH 06/10] tests/qapi-schema: Cover union types with base, (continued)
[Qemu-devel] [PATCH 02/10] tests/qapi-schema: Cover optional command arguments, Markus Armbruster, 2014/02/06
[Qemu-devel] [PATCH 08/10] qapi: Drop nonsensical header guard in generated qapi-visit.c, Markus Armbruster, 2014/02/06
[Qemu-devel] [PATCH 09/10] qapi: Drop unused code in qapi-commands.py, Markus Armbruster, 2014/02/06
[Qemu-devel] [PATCH 04/10] tests/qapi-schema: Cover anonymous union types, Markus Armbruster, 2014/02/06