diff mbox

[09/14] blockdev: Plug memory leak in drive_init()

Message ID 1401125835-21765-10-git-send-email-armbru@redhat.com
State New
Headers show

Commit Message

Markus Armbruster May 26, 2014, 5:37 p.m. UTC
Introduced in commit f298d07.  Spotted by Coverity.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 blockdev.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Benoît Canet May 27, 2014, 10:48 a.m. UTC | #1
The Monday 26 May 2014 à 19:37:10 (+0200), Markus Armbruster wrote :
> Introduced in commit f298d07.  Spotted by Coverity.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  blockdev.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/blockdev.c b/blockdev.c
> index 6460c70..7ec7d79 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -941,6 +941,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
>  
>      /* Actual block device init: Functionality shared with blockdev-add */
>      dinfo = blockdev_init(filename, bs_opts, &local_err);
> +    bs_opts = NULL;
>      if (dinfo == NULL) {
>          if (local_err) {
>              qerror_report_err(local_err);
> @@ -978,6 +979,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
>  
>  fail:
>      qemu_opts_del(legacy_opts);
> +    QDECREF(bs_opts);
>      return dinfo;
>  }
>  
> -- 
> 1.9.3
> 
> 

This commits seems to fix two thing a leak and a double free.
Maybe reflecting this on the commit message would make the bs_opts = NULL; clearer.

Best regards

Benoît
Markus Armbruster May 27, 2014, 4:13 p.m. UTC | #2
Benoît Canet <benoit.canet@irqsave.net> writes:

> The Monday 26 May 2014 à 19:37:10 (+0200), Markus Armbruster wrote :
>> Introduced in commit f298d07.  Spotted by Coverity.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  blockdev.c | 2 ++
>>  1 file changed, 2 insertions(+)
>> 
>> diff --git a/blockdev.c b/blockdev.c
>> index 6460c70..7ec7d79 100644
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -941,6 +941,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
>>  
>>      /* Actual block device init: Functionality shared with blockdev-add */
>>      dinfo = blockdev_init(filename, bs_opts, &local_err);
>> +    bs_opts = NULL;
>>      if (dinfo == NULL) {
>>          if (local_err) {
>>              qerror_report_err(local_err);
>> @@ -978,6 +979,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
>>  
>>  fail:
>>      qemu_opts_del(legacy_opts);
>> +    QDECREF(bs_opts);
>>      return dinfo;
>>  }
>>  
>> -- 
>> 1.9.3
>> 
>> 
>
> This commits seems to fix two thing a leak and a double free.
> Maybe reflecting this on the commit message would make the bs_opts =
> NULL; clearer.

I'm blind.  Can you explain the double free to me?
Markus Armbruster May 27, 2014, 7:11 p.m. UTC | #3
Benoît Canet <benoit.canet@irqsave.net> writes:

> The Tuesday 27 May 2014 à 18:13:12 (+0200), Markus Armbruster wrote :
>> Benoît Canet <benoit.canet@irqsave.net> writes:
>> 
>> > The Monday 26 May 2014 à 19:37:10 (+0200), Markus Armbruster wrote :
>> >> Introduced in commit f298d07.  Spotted by Coverity.
>> >> 
>> >> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> >> ---
>> >>  blockdev.c | 2 ++
>> >>  1 file changed, 2 insertions(+)
>> >> 
>> >> diff --git a/blockdev.c b/blockdev.c
>> >> index 6460c70..7ec7d79 100644
>> >> --- a/blockdev.c
>> >> +++ b/blockdev.c
>> >> @@ -941,6 +941,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
>> >>  
>> >>      /* Actual block device init: Functionality shared with blockdev-add */
>> >>      dinfo = blockdev_init(filename, bs_opts, &local_err);
>> >> +    bs_opts = NULL;
>
> What is the purpose of this line ? I though it was to avoid double unref.

Before this patch, bs_opts gets leaked on any path from its qdict_new()
that doesn't go through blockdev_init().

The new line below frees it, but without the line above, it would free
it a second time on paths that go through blockdev_init().

Clear now?

>> >>      if (dinfo == NULL) {
>> >>          if (local_err) {
>> >>              qerror_report_err(local_err);
>> >> @@ -978,6 +979,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
>> >>  
>> >>  fail:
>> >>      qemu_opts_del(legacy_opts);
>> >> +    QDECREF(bs_opts);
>> >>      return dinfo;
>> >>  }
>> >>  
>> >> -- 
>> >> 1.9.3
>> >> 
>> >> 
>> >
>> > This commits seems to fix two thing a leak and a double free.
>> > Maybe reflecting this on the commit message would make the bs_opts =
>> > NULL; clearer.
>> 
>> I'm blind.  Can you explain the double free to me?
Markus Armbruster May 27, 2014, 7:44 p.m. UTC | #4
Benoît Canet <benoit.canet@irqsave.net> writes:

> The Tuesday 27 May 2014 à 21:11:45 (+0200), Markus Armbruster wrote :
>> Benoît Canet <benoit.canet@irqsave.net> writes:
>> 
>> > The Tuesday 27 May 2014 à 18:13:12 (+0200), Markus Armbruster wrote :
>> >> Benoît Canet <benoit.canet@irqsave.net> writes:
>> >> 
>> >> > The Monday 26 May 2014 à 19:37:10 (+0200), Markus Armbruster wrote :
>> >> >> Introduced in commit f298d07.  Spotted by Coverity.
>> >> >> 
>> >> >> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> >> >> ---
>> >> >>  blockdev.c | 2 ++
>> >> >>  1 file changed, 2 insertions(+)
>> >> >> 
>> >> >> diff --git a/blockdev.c b/blockdev.c
>> >> >> index 6460c70..7ec7d79 100644
>> >> >> --- a/blockdev.c
>> >> >> +++ b/blockdev.c
>> >> >> @@ -941,6 +941,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
>> >> >>  
>> >> >>      /* Actual block device init: Functionality shared with blockdev-add */
>> >> >>      dinfo = blockdev_init(filename, bs_opts, &local_err);
>> >> >> +    bs_opts = NULL;
>> >
>> > What is the purpose of this line ? I though it was to avoid double unref.
>> 
>> Before this patch, bs_opts gets leaked on any path from its qdict_new()
>> that doesn't go through blockdev_init().
>> 
>> The new line below frees it, but without the line above, it would free
>> it a second time on paths that go through blockdev_init().
>> 
>> Clear now?
>
> Clear from the start it fixes a potential double free.
> "This commits seems to fix two thing a leak and a double free."

Well, before the patch, the leak exists, but there is no double-free.

The patch fixes only one thing: the leak.  It takes care not to break
things by freeing when it shouldn't.

Do you still think the commit message should be amended?  How?

[...]
Benoît Canet May 27, 2014, 7:50 p.m. UTC | #5
The Tuesday 27 May 2014 à 18:13:12 (+0200), Markus Armbruster wrote :
> Benoît Canet <benoit.canet@irqsave.net> writes:
> 
> > The Monday 26 May 2014 à 19:37:10 (+0200), Markus Armbruster wrote :
> >> Introduced in commit f298d07.  Spotted by Coverity.
> >> 
> >> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> >> ---
> >>  blockdev.c | 2 ++
> >>  1 file changed, 2 insertions(+)
> >> 
> >> diff --git a/blockdev.c b/blockdev.c
> >> index 6460c70..7ec7d79 100644
> >> --- a/blockdev.c
> >> +++ b/blockdev.c
> >> @@ -941,6 +941,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
> >>  
> >>      /* Actual block device init: Functionality shared with blockdev-add */
> >>      dinfo = blockdev_init(filename, bs_opts, &local_err);
> >> +    bs_opts = NULL;

What is the purpose of this line ? I though it was to avoid double unref.

> >>      if (dinfo == NULL) {
> >>          if (local_err) {
> >>              qerror_report_err(local_err);
> >> @@ -978,6 +979,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
> >>  
> >>  fail:
> >>      qemu_opts_del(legacy_opts);
> >> +    QDECREF(bs_opts);
> >>      return dinfo;
> >>  }
> >>  
> >> -- 
> >> 1.9.3
> >> 
> >> 
> >
> > This commits seems to fix two thing a leak and a double free.
> > Maybe reflecting this on the commit message would make the bs_opts =
> > NULL; clearer.
> 
> I'm blind.  Can you explain the double free to me?
Benoît Canet May 27, 2014, 9 p.m. UTC | #6
The Tuesday 27 May 2014 à 21:11:45 (+0200), Markus Armbruster wrote :
> Benoît Canet <benoit.canet@irqsave.net> writes:
> 
> > The Tuesday 27 May 2014 à 18:13:12 (+0200), Markus Armbruster wrote :
> >> Benoît Canet <benoit.canet@irqsave.net> writes:
> >> 
> >> > The Monday 26 May 2014 à 19:37:10 (+0200), Markus Armbruster wrote :
> >> >> Introduced in commit f298d07.  Spotted by Coverity.
> >> >> 
> >> >> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> >> >> ---
> >> >>  blockdev.c | 2 ++
> >> >>  1 file changed, 2 insertions(+)
> >> >> 
> >> >> diff --git a/blockdev.c b/blockdev.c
> >> >> index 6460c70..7ec7d79 100644
> >> >> --- a/blockdev.c
> >> >> +++ b/blockdev.c
> >> >> @@ -941,6 +941,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
> >> >>  
> >> >>      /* Actual block device init: Functionality shared with blockdev-add */
> >> >>      dinfo = blockdev_init(filename, bs_opts, &local_err);
> >> >> +    bs_opts = NULL;
> >
> > What is the purpose of this line ? I though it was to avoid double unref.
> 
> Before this patch, bs_opts gets leaked on any path from its qdict_new()
> that doesn't go through blockdev_init().
> 
> The new line below frees it, but without the line above, it would free
> it a second time on paths that go through blockdev_init().
> 
> Clear now?

Clear from the start it fixes a potential double free.
"This commits seems to fix two thing a leak and a double free."

Best regards

Benoît

> 
> >> >>      if (dinfo == NULL) {
> >> >>          if (local_err) {
> >> >>              qerror_report_err(local_err);
> >> >> @@ -978,6 +979,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
> >> >>  
> >> >>  fail:
> >> >>      qemu_opts_del(legacy_opts);
> >> >> +    QDECREF(bs_opts);
> >> >>      return dinfo;
> >> >>  }
> >> >>  
> >> >> -- 
> >> >> 1.9.3
> >> >> 
> >> >> 
> >> >
> >> > This commits seems to fix two thing a leak and a double free.
> >> > Maybe reflecting this on the commit message would make the bs_opts =
> >> > NULL; clearer.
> >> 
> >> I'm blind.  Can you explain the double free to me?
>
Benoît Canet May 27, 2014, 9:43 p.m. UTC | #7
The Tuesday 27 May 2014 à 21:44:15 (+0200), Markus Armbruster wrote :
> Benoît Canet <benoit.canet@irqsave.net> writes:
> 
> > The Tuesday 27 May 2014 à 21:11:45 (+0200), Markus Armbruster wrote :
> >> Benoît Canet <benoit.canet@irqsave.net> writes:
> >> 
> >> > The Tuesday 27 May 2014 à 18:13:12 (+0200), Markus Armbruster wrote :
> >> >> Benoît Canet <benoit.canet@irqsave.net> writes:
> >> >> 
> >> >> > The Monday 26 May 2014 à 19:37:10 (+0200), Markus Armbruster wrote :
> >> >> >> Introduced in commit f298d07.  Spotted by Coverity.
> >> >> >> 
> >> >> >> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> >> >> >> ---
> >> >> >>  blockdev.c | 2 ++
> >> >> >>  1 file changed, 2 insertions(+)
> >> >> >> 
> >> >> >> diff --git a/blockdev.c b/blockdev.c
> >> >> >> index 6460c70..7ec7d79 100644
> >> >> >> --- a/blockdev.c
> >> >> >> +++ b/blockdev.c
> >> >> >> @@ -941,6 +941,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
> >> >> >>  
> >> >> >>      /* Actual block device init: Functionality shared with blockdev-add */
> >> >> >>      dinfo = blockdev_init(filename, bs_opts, &local_err);
> >> >> >> +    bs_opts = NULL;
> >> >
> >> > What is the purpose of this line ? I though it was to avoid double unref.
> >> 
> >> Before this patch, bs_opts gets leaked on any path from its qdict_new()
> >> that doesn't go through blockdev_init().
> >> 
> >> The new line below frees it, but without the line above, it would free
> >> it a second time on paths that go through blockdev_init().
> >> 
> >> Clear now?
> >
> > Clear from the start it fixes a potential double free.
> > "This commits seems to fix two thing a leak and a double free."
> 
> Well, before the patch, the leak exists, but there is no double-free.
> 
> The patch fixes only one thing: the leak.  It takes care not to break
> things by freeing when it shouldn't.
> 
> Do you still think the commit message should be amended?  How?

Maybe just says it also take care not to introduce a double free.

Best regards

Benoît

> 
> [...]
>
Markus Armbruster May 28, 2014, 8:06 a.m. UTC | #8
Benoît Canet <benoit.canet@irqsave.net> writes:

> The Tuesday 27 May 2014 à 21:44:15 (+0200), Markus Armbruster wrote :
>> Benoît Canet <benoit.canet@irqsave.net> writes:
>> 
>> > The Tuesday 27 May 2014 à 21:11:45 (+0200), Markus Armbruster wrote :
>> >> Benoît Canet <benoit.canet@irqsave.net> writes:
>> >> 
>> >> > The Tuesday 27 May 2014 à 18:13:12 (+0200), Markus Armbruster wrote :
>> >> >> Benoît Canet <benoit.canet@irqsave.net> writes:
>> >> >> 
>> >> >> > The Monday 26 May 2014 à 19:37:10 (+0200), Markus Armbruster wrote :
>> >> >> >> Introduced in commit f298d07.  Spotted by Coverity.
>> >> >> >> 
>> >> >> >> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> >> >> >> ---
>> >> >> >>  blockdev.c | 2 ++
>> >> >> >>  1 file changed, 2 insertions(+)
>> >> >> >> 
>> >> >> >> diff --git a/blockdev.c b/blockdev.c
>> >> >> >> index 6460c70..7ec7d79 100644
>> >> >> >> --- a/blockdev.c
>> >> >> >> +++ b/blockdev.c
>> >> >> >> @@ -941,6 +941,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
>> >> >> >>  
>> >> >> >>      /* Actual block device init: Functionality shared with blockdev-add */
>> >> >> >>      dinfo = blockdev_init(filename, bs_opts, &local_err);
>> >> >> >> +    bs_opts = NULL;
>> >> >
>> >> > What is the purpose of this line ? I though it was to avoid double unref.
>> >> 
>> >> Before this patch, bs_opts gets leaked on any path from its qdict_new()
>> >> that doesn't go through blockdev_init().
>> >> 
>> >> The new line below frees it, but without the line above, it would free
>> >> it a second time on paths that go through blockdev_init().
>> >> 
>> >> Clear now?
>> >
>> > Clear from the start it fixes a potential double free.
>> > "This commits seems to fix two thing a leak and a double free."
>> 
>> Well, before the patch, the leak exists, but there is no double-free.
>> 
>> The patch fixes only one thing: the leak.  It takes care not to break
>> things by freeing when it shouldn't.
>> 
>> Do you still think the commit message should be amended?  How?
>
> Maybe just says it also take care not to introduce a double free.

Adding this paragraph:

    bs_opts is leaked on all paths from its qdev_new() that don't got
    through blockdev_init().  Add the missing QDECREF(), and zap bs_opts
    after blockdev_init(), so the new QDECREF() does nothing when we go
    through blockdev_init().

Thanks!
diff mbox

Patch

diff --git a/blockdev.c b/blockdev.c
index 6460c70..7ec7d79 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -941,6 +941,7 @@  DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
 
     /* Actual block device init: Functionality shared with blockdev-add */
     dinfo = blockdev_init(filename, bs_opts, &local_err);
+    bs_opts = NULL;
     if (dinfo == NULL) {
         if (local_err) {
             qerror_report_err(local_err);
@@ -978,6 +979,7 @@  DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
 
 fail:
     qemu_opts_del(legacy_opts);
+    QDECREF(bs_opts);
     return dinfo;
 }