From: Paolo Bonzini <pbonzini@redhat.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: kwolf@redhat.com, qemu-devel@nongnu.org, aliguori@amazon.com,
mdroth@linux.vnet.ibm.com
Subject: Re: [Qemu-devel] [PATCH 10/10] qapi: Clean up null checking in generated visitors
Date: Tue, 11 Feb 2014 10:06:27 +0100 [thread overview]
Message-ID: <52F9E813.3070402@redhat.com> (raw)
In-Reply-To: <87ob2f6qqd.fsf@blackfin.pond.sub.org>
Il 10/02/2014 14:29, Markus Armbruster ha scritto:
> Markus Armbruster <armbru@redhat.com> writes:
>
>> Paolo Bonzini <pbonzini@redhat.com> 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.
Patch 10 is okay then!
We really should write down all of this. Thanks for spelling it down
for us! :(
Paolo
> 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.
>
> [...]
>
next prev parent reply other threads:[~2014-02-11 9:06 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-02-06 14:29 [Qemu-devel] [PATCH 00/10] qapi: Test coverage & clean up generated code Markus Armbruster
2014-02-06 14:29 ` [Qemu-devel] [PATCH 01/10] tests/qapi-schema: Actually check successful QMP command response Markus Armbruster
2014-02-07 2:09 ` Eric Blake
2014-02-07 7:37 ` Markus Armbruster
2014-02-06 14:29 ` [Qemu-devel] [PATCH 02/10] tests/qapi-schema: Cover optional command arguments Markus Armbruster
2014-02-07 2:30 ` Eric Blake
2014-02-06 14:29 ` [Qemu-devel] [PATCH 03/10] tests/qapi-schema: Cover simple argument types Markus Armbruster
2014-02-07 2:32 ` Eric Blake
2014-02-06 14:29 ` [Qemu-devel] [PATCH 04/10] tests/qapi-schema: Cover anonymous union types Markus Armbruster
2014-02-07 2:35 ` Eric Blake
2014-02-06 14:29 ` [Qemu-devel] [PATCH 05/10] tests/qapi-schema: Cover complex types with base Markus Armbruster
2014-02-07 2:38 ` Eric Blake
2014-02-06 14:29 ` [Qemu-devel] [PATCH 06/10] tests/qapi-schema: Cover union " Markus Armbruster
2014-02-07 2:40 ` Eric Blake
2014-02-06 14:29 ` [Qemu-devel] [PATCH 07/10] tests/qapi-schema: Cover flat union types Markus Armbruster
2014-02-07 2:51 ` Eric Blake
2014-02-06 14:29 ` [Qemu-devel] [PATCH 08/10] qapi: Drop nonsensical header guard in generated qapi-visit.c Markus Armbruster
2014-02-07 2:52 ` Eric Blake
2014-02-06 14:29 ` [Qemu-devel] [PATCH 09/10] qapi: Drop unused code in qapi-commands.py Markus Armbruster
2014-02-07 2:56 ` Eric Blake
2014-02-06 14:30 ` [Qemu-devel] [PATCH 10/10] qapi: Clean up null checking in generated visitors Markus Armbruster
2014-02-07 3:10 ` Eric Blake
2014-02-07 7:34 ` Markus Armbruster
2014-02-07 12:42 ` Paolo Bonzini
2014-02-07 14:23 ` Markus Armbruster
2014-02-07 14:45 ` Paolo Bonzini
2014-02-10 13:29 ` Markus Armbruster
2014-02-11 9:06 ` Paolo Bonzini [this message]
2014-02-11 12:35 ` Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52F9E813.3070402@redhat.com \
--to=pbonzini@redhat.com \
--cc=aliguori@amazon.com \
--cc=armbru@redhat.com \
--cc=kwolf@redhat.com \
--cc=mdroth@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).