qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Eric Blake <eblake@redhat.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: qemu-devel@nongnu.org, mdroth@linux.vnet.ibm.com
Subject: Re: [Qemu-devel] [PATCH v6 20/26] qapi: Fix output visitor to return qnull() instead of NULL
Date: Sat, 12 Sep 2015 06:16:08 -0600	[thread overview]
Message-ID: <55F41788.6030008@redhat.com> (raw)
In-Reply-To: <87a8ssf47y.fsf@blackfin.pond.sub.org>

[-- Attachment #1: Type: text/plain, Size: 3914 bytes --]

On 09/12/2015 02:10 AM, Markus Armbruster wrote:

> Relatively harmless, because the qnull_ singleton is static.  Worth
> fixing anyway, of course.
> 
>>> I'm still investigating, and may be able to find the patch
>>
>> Squash this in, and you can have:
>> Reviewed-by: Eric Blake <eblake@redhat.com>

Well, your further questions are spot on; my squash proposal isn't quite
right.


> I put the qnull() in qmp_output_first() to avoid (QObject *)0 entirely.
> Also because that's where I found the FIXME :)
> 
> You lift it into one of two callers.  Impact:
> 
> * qmp_output_get_qobject()
> 
>   - master: return NULL when !e || !e->value
> 
>   - my patch: return qnull() when !e
>               return NULL when !e->value
> 
>   - your patch: return qnull() when !e || !e->value

The leak in your patch was that qnull() increments the count, then
qmp_output_get_object() also increments the count.

I guess I'll have to investigate where e->value can be set to NULL to
see if my idea was safe, or if we'd have to do something even different.

If this were the only caller, then I guess we could always do something
like this in qmp_output_first(), leaving the possibility of returning
NULL for e->value:

if (!e) {
    obj = qnull();
    qobject_decref(obj); /* Caller will again increment refcount */
    return obj;
}

But it's not the only caller.

> 
> * qmp_output_visitor_cleanup()
> 
>   - master: root = NULL when when !e || !e->value
> 
>   - my patch: root = qnull() when !e
>               root = NULL when !e->value
> 
>   - your patch: root = NULL when when !e || !e->value

And calls qobject_decref(root), but that is safe on NULL.

Here, your patch ends up with a net 0 refcnt on qnull() (incremented in
qmp_output_first(), decremented in the cleanup), but my idea above to
pre-decrement would be wrong.

Another option would be to keep your patch to qmp_output_first(), but
then fix qmp_output_get_object() to special case it it has an instance
of QNull (no refcnt change) vs. anything else (qobject_incref).  But
that feels gross.

> 
> where e = QTAILQ_LAST(&qov->stack, QStack)
> 
> Questions:
> 
> * How can e become NULL?
> 
>   The only place that pushes onto &qov->stack appears to be
>   qmp_output_push_obj().  Can obviously push e with !e->value, but can't
>   push null e.

My understanding is that qov->stack corresponds to nesting levels of {}
or [] in the JSON code.  The testsuite shows a case where the stack is
empty as one case where e is NULL, but if e is non-NULL, I'm not sure
whether e->value can ever be NULL.  I'll have to read the code more closely.

> 
> * What about qmp_output_last()?
> 
>   Why does qmp_output_first() check for !e, but not qmp_output_last()?
> 
>   My patch makes them less symmetric (bad smell).  Yours makes them more
>   symmetric, but not quite.

Which is awkward in its own right.

> 
> * How does this contraption work?

Indeed. Without reading further, we're both shooting in the dark for
something that makes tests pass, but without being a clean interface.

How about this: go ahead with your series as proposed, with the squash
hunk to tests/ to avoid the leak in the testsuite, but leaving the leak
in qmp_output_get_object(), and we address the leak in a followup patch.
 refcnt is size_t, so on 32-bit platforms, it could roll over after 4G
repeats of the leak and cause catastrophe, but I don't think we are
outputting qnull() frequently enough for the leak to bite while we wait
for a followup patch.

The followup patch(es) will then have to include some contract
documentation, so that we track what we learned while investigating the
code, and so that the next reader has more than just code to start from.


-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

  reply	other threads:[~2015-09-12 12:16 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-11 19:17 [Qemu-devel] [PATCH v6 00/26] qapi: QMP introspection Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 01/26] qapi: Rename class QAPISchema to QAPISchemaParser Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 02/26] qapi: New QAPISchema intermediate reperesentation Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 03/26] qapi: QAPISchema code generation helper methods Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 04/26] qapi: New QAPISchemaVisitor Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 05/26] tests/qapi-schema: Convert test harness to QAPISchemaVisitor Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 06/26] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 07/26] qapi-visit: Convert to QAPISchemaVisitor, fixing bugs Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 08/26] qapi-commands: Convert to QAPISchemaVisitor Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 09/26] qapi: De-duplicate enum code generation Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 10/26] qapi-event: Eliminate global variable event_enum_value Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 11/26] qapi-event: Convert to QAPISchemaVisitor, fixing data with base Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 12/26] qapi: Replace dirty is_c_ptr() by method c_null() Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 13/26] qapi: Clean up after recent conversions to QAPISchemaVisitor Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 14/26] qapi-visit: Rearrange code a bit Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 15/26] qapi-commands: Rearrange code Markus Armbruster
2015-09-11 19:17 ` [Qemu-devel] [PATCH v6 16/26] qapi: Rename qmp_marshal_input_FOO() to qmp_marshal_FOO() Markus Armbruster
2015-09-11 19:18 ` [Qemu-devel] [PATCH v6 17/26] qapi: De-duplicate parameter list generation Markus Armbruster
2015-09-11 19:18 ` [Qemu-devel] [PATCH v6 18/26] qapi-commands: De-duplicate output marshaling functions Markus Armbruster
2015-09-11 19:18 ` [Qemu-devel] [PATCH v6 19/26] qapi: Improve built-in type documentation Markus Armbruster
2015-09-11 19:18 ` [Qemu-devel] [PATCH v6 20/26] qapi: Fix output visitor to return qnull() instead of NULL Markus Armbruster
2015-09-11 20:43   ` Eric Blake
2015-09-11 21:01     ` Eric Blake
2015-09-12  8:10       ` Markus Armbruster
2015-09-12 12:16         ` Eric Blake [this message]
2015-09-12 13:42           ` Eric Blake
2015-09-12 13:55             ` Eric Blake
2015-09-12 14:11           ` Markus Armbruster
2015-09-12 14:17             ` Eric Blake
2015-09-11 19:18 ` [Qemu-devel] [PATCH v6 21/26] qapi: Introduce a first class 'any' type Markus Armbruster
2015-09-11 19:18 ` [Qemu-devel] [PATCH v6 22/26] qom: Don't use 'gen': false for qom-get, qom-set, object-add Markus Armbruster
2015-09-11 19:18 ` [Qemu-devel] [PATCH v6 23/26] qapi-schema: Fix up misleading specification of netdev_add Markus Armbruster
2015-09-11 19:18 ` [Qemu-devel] [PATCH v6 24/26] qapi: Pseudo-type '**' is now unused, drop it Markus Armbruster
2015-09-11 19:18 ` [Qemu-devel] [PATCH v6 25/26] qapi: New QMP command query-qmp-schema for QMP introspection Markus Armbruster
2015-09-11 19:18 ` [Qemu-devel] [PATCH v6 26/26] qapi-introspect: Hide type names 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=55F41788.6030008@redhat.com \
    --to=eblake@redhat.com \
    --cc=armbru@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).