qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Laszlo Ersek <lersek@redhat.com>
To: Luiz Capitulino <lcapitulino@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v2 01/17] qapi: fix error propagation
Date: Fri, 13 Jul 2012 19:30:37 +0200	[thread overview]
Message-ID: <50005B3D.2070009@redhat.com> (raw)
In-Reply-To: <20120713133852.3a446672@doriath.home>

On 07/13/12 18:38, Luiz Capitulino wrote:
> On Wed, 13 Jun 2012 10:22:32 +0200
> Laszlo Ersek <lersek@redhat.com> wrote:
> 
>> From: Paolo Bonzini <pbonzini@redhat.com>
>>
>> Don't overwrite / leak previously set errors.
> 
> Can you elaborate a bit more? It's not clear to me where the bug is.

Suppose you encounter the first error on the normal path, while a bunch
of objects is being constructed / composed. You set the error
accordingly and start to unwind the stack, tearing down objects
previously composed fully or partially. While doing this, you encounter
another error. If you call error_set() or error_propagate() now, the
first error is leaked. To avoid this, you have to check.

This change saves you the checks during stack unwinding, keeps the first
error stored (which is more important than any destructor errors, since
the latter could be the direct consequence of the first error and
aborting further processing). Second and later errors attempted to be
set via error_set() are simply not formatted, while second and later
errors attempted to be propagated with error_propagate() are released
(as there are two errors and we keep only one).

See "qapi: introduce OptsVisitor", function opts_end_struct(), comment
"we should have processed all (distinct) QemuOpt instances". If we abort
processing due to some error, there may be leftover options. We
shouldn't overwrite the first (real) error with this bogus one.

The stack is unwound in this case by the generated code -- if some
deeper part of OptsVisitor sets an error, the generated code will make
sure opts_end_struct() is called the right number of times.


> 
> More comments below.
> 
>> Don't try to end a container that could not be started.
>>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>  error.h                        |    4 +-
>>  error.c                        |    4 +-
>>  qapi/qapi-visit-core.c         |   10 +--
>>  tests/test-qmp-input-visitor.c |   24 +++++---
>>  docs/qapi-code-gen.txt         |    2 +
>>  scripts/qapi-visit.py          |  129 +++++++++++++++++++++++----------------
>>  6 files changed, 102 insertions(+), 71 deletions(-)
>>
>> diff --git a/error.h b/error.h
>> index 45ff6c1..6898f84 100644
>> --- a/error.h
>> +++ b/error.h
>> @@ -24,7 +24,7 @@ typedef struct Error Error;
>>  /**
>>   * Set an indirect pointer to an error given a printf-style format parameter.
>>   * Currently, qerror.h defines these error formats.  This function is not
>> - * meant to be used outside of QEMU.
>> + * meant to be used outside of QEMU.  Errors after the first are discarded.
>>   */
>>  void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
>>  
>> @@ -57,7 +57,7 @@ void error_set_field(Error *err, const char *field, const char *value);
>>  /**
>>   * Propagate an error to an indirect pointer to an error.  This function will
>>   * always transfer ownership of the error reference and handles the case where
>> - * dst_err is NULL correctly.
>> + * dst_err is NULL correctly.  Errors after the first are discarded.
>>   */
>>  void error_propagate(Error **dst_err, Error *local_err);
>>  
>> diff --git a/error.c b/error.c
>> index a52b771..0177972 100644
>> --- a/error.c
>> +++ b/error.c
>> @@ -29,7 +29,7 @@ void error_set(Error **errp, const char *fmt, ...)
>>      Error *err;
>>      va_list ap;
>>  
>> -    if (errp == NULL) {
>> +    if (errp == NULL || *errp != NULL) {
> 
> I think we should use assert() here.
> 
> If the error is already set, that most probably indicates a bug in the caller, as
> it's the caller's responsibility to decide which error to return.

I believe we had a good argument against this, but I can't precisely
recall (or find) it now. Paolo, do you remember? Can you please both
search your respective mailboxen for Message-ID
<4FB21B71.7030804@redhat.com>? That's where we started to discuss this.

I believe I saw some paths in the code that tripped on this leak, and
generally keeping the first error seemed like a good idea.
opts_end_struct() originally checked for any pre-existent error
explicitly, but then the check was moved to the common code.


> 
>>          return;
>>      }
>>  
>> @@ -132,7 +132,7 @@ bool error_is_type(Error *err, const char *fmt)
>>  
>>  void error_propagate(Error **dst_err, Error *local_err)
>>  {
>> -    if (dst_err) {
>> +    if (dst_err && !*dst_err) {
>>          *dst_err = local_err;
>>      } else if (local_err) {
>>          error_free(local_err);
>> diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
>> index ffffbf7..0a513d2 100644
>> --- a/qapi/qapi-visit-core.c
>> +++ b/qapi/qapi-visit-core.c
>> @@ -39,9 +39,8 @@ void visit_start_struct(Visitor *v, void **obj, const char *kind,
>>  
>>  void visit_end_struct(Visitor *v, Error **errp)
>>  {
>> -    if (!error_is_set(errp)) {
>> -        v->end_struct(v, errp);
>> -    }
> 
> Is this the ending of a container that could not be started? But if it couldn't
> be started, then errp be will be set and we won't try to end it, no?
> 
>> +    assert(!error_is_set(errp));
>> +    v->end_struct(v, errp);
>>  }

(Perhaps I'm misunderstanding.)

Exactly as you say. That's why we replace the check with an assert.

(This seems to be your last question for this patch, so I'm cutting the
rest.)

Thanks,
Laszlo

  reply	other threads:[~2012-07-13 17:29 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-06-13  8:22 [Qemu-devel] [PATCH v2 00/17] introduce OptsVisitor, rebase -net/-netdev parsing Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 01/17] qapi: fix error propagation Laszlo Ersek
2012-07-13 16:38   ` Luiz Capitulino
2012-07-13 17:30     ` Laszlo Ersek [this message]
2012-07-13 19:11       ` Paolo Bonzini
2012-07-13 20:11         ` Laszlo Ersek
2012-07-16 17:12         ` Luiz Capitulino
2012-07-16 20:31           ` Laszlo Ersek
2012-07-16 20:44             ` Luiz Capitulino
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 02/17] qapi: generate C types for fixed-width integers Laszlo Ersek
2012-06-13 10:48   ` Paolo Bonzini
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 03/17] qapi: introduce "size" type Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 04/17] expose QemuOpt and QemuOpts struct definitions to interested parties Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 05/17] qapi: introduce OptsVisitor Laszlo Ersek
2012-06-13 10:50   ` Paolo Bonzini
2012-06-13 14:03     ` Laszlo Ersek
2012-07-13 16:51   ` Luiz Capitulino
2012-07-13 22:48     ` Laszlo Ersek
2012-07-13 23:09       ` Laszlo Ersek
2012-07-16 17:30       ` Luiz Capitulino
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 06/17] qapi schema: remove trailing whitespace Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 07/17] qapi schema: add Netdev types Laszlo Ersek
2012-06-13 10:50   ` Paolo Bonzini
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 08/17] hw, net: "net_client_type" -> "NetClientOptionsKind" (qapi-generated) Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 09/17] convert net_client_init() to OptsVisitor Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 10/17] convert net_init_nic() to NetClientOptions Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 11/17] convert net_init_dump() " Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 12/17] convert net_init_slirp() " Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 13/17] convert net_init_socket() " Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 14/17] convert net_init_vde() " Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 15/17] convert net_init_tap() " Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 16/17] convert net_init_bridge() " Laszlo Ersek
2012-06-13  8:22 ` [Qemu-devel] [PATCH v2 17/17] remove unused QemuOpts parameter from net init functions Laszlo Ersek
2012-06-13 10:54 ` [Qemu-devel] [PATCH v2 00/17] introduce OptsVisitor, rebase -net/-netdev parsing Paolo Bonzini
2012-07-01 13:33   ` Paolo Bonzini
2012-07-02 13:17     ` Luiz Capitulino
2012-07-13 16:46 ` Luiz Capitulino
2012-07-13 19:28   ` Laszlo Ersek

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=50005B3D.2070009@redhat.com \
    --to=lersek@redhat.com \
    --cc=lcapitulino@redhat.com \
    --cc=pbonzini@redhat.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).