qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] usb-storage: fix possible memory leak and missi


From: Gonglei (Arei)
Subject: Re: [Qemu-devel] [PATCH] usb-storage: fix possible memory leak and missing error message
Date: Thu, 18 Sep 2014 09:09:14 +0000

> >> > ---
> >> >  hw/usb/dev-storage.c | 11 ++++++-----
> >> >  1 file changed, 6 insertions(+), 5 deletions(-)
> >> >
> >> > diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
> >> > index 5c51ac0..cabd053 100644
> >> > --- a/hw/usb/dev-storage.c
> >> > +++ b/hw/usb/dev-storage.c
> >> > @@ -599,7 +599,6 @@ static int usb_msd_initfn_storage(USBDevice
> *dev)
> >> >  {
> >> >      MSDState *s = DO_UPCAST(MSDState, dev, dev);
> >> >      BlockDriverState *bs = s->conf.bs;
> >> > -    SCSIDevice *scsi_dev;
> >> >      Error *err = NULL;
> >> >
> >> >      if (!bs) {
> >> > @@ -625,10 +624,12 @@ static int usb_msd_initfn_storage(USBDevice
> *dev)
> >> >      usb_desc_init(dev);
> >> >      scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
> >> >                   &usb_msd_scsi_info_storage, NULL);
> >> > -    scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs,
> 0, !!s->removable,
> >> > -                                         s->conf.bootindex,
> dev->serial,
> >> > -                                         &err);
> >> > -    if (!scsi_dev) {
> >> > +    scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
> >> > +                              s->conf.bootindex, dev->serial,
> >> > +                              &err);
> >> > +    if (err) {
> >> > +        error_report("%s", error_get_pretty(err));
> >> > +        error_free(err);
> >> >          return -1;
> >> >      }
> >> >      s->bus.qbus.allow_hotplug = 0;
> >>
> >> I'd keep the original condition and just fix the error message loss /
> >> error object leak:
> >>
> >> diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
> >> index ae4efcb..f731b0a 100644
> >> --- a/hw/usb/dev-storage.c
> >> +++ b/hw/usb/dev-storage.c
> >> @@ -624,6 +624,8 @@ static int usb_msd_initfn_storage(USBDevice *dev)
> >>                                           s->conf.bootindex,
> >> dev->serial,
> >>                                           &err);
> >>      if (!scsi_dev) {
> >> +        error_report("%s", error_get_pretty(err));
> >> +        error_free(err);
> >>          return -1;
> >>      }
> >>      s->bus.qbus.allow_hotplug = 0;
> >>
> >> Partly because it makes the fix more obvious, partly because I prefer
> >> checking the function value when it is available.  Matter of taste.
> >>
> > Hmm..
> >
> > The main problem is I'm afraid the scenario when scsi_dev
> > is NULL the err is NULL too in someday. I have fixed a similar issue
> > and you have reviewed. :)
> 
> Short answer: doesn't help, and you shouldn't be afraid anyway.
> 
> Now the long answer :)
> 
> Basic rules about returning errors through Error **errp parameters:
> 
> 1. The errp argument may be null.
> 
> 2. If it isn't, then it points to null.
> 
> 3. The function either succeeds or fails.
> 
> 4. If the function succeeds, it doesn't touch *errp.
> 
> 5. If the function fails, and
> 
>    a. if errp isn't null, it creates an Error object and returns it in
>    *errp.  The caller is responsible for freeing it.
> 
>    b. if errp is null, no Error object is created.
> 
> Corollary: when you pass a non-null errp argument, *errp is null exactly
> on success.
> 
> Rule 3 connects the Error contract with what else the function's
> supposed to do on success and on failure.  In particular with the return
> value.
> 
> Common case: a function returns a pointer to something on success, null
> pointer on failure.  When you pass a non-null errp, argument, *errp is
> null exactly when the function value is non-null.  In other words,
> either the value or *errp is null.
> 
> To detect errors, you can either check the function value, or your errp
> argument.
> 
> If you detect an error, you can either handle it locally, or propagate
> it to your caller.
> 
> Example: consider a function new_foo() returning a newly allocated Foo
> on success, null on error.  Any error we want to propagate.
> 
> Checking the errp argument:
> 
>     Error *local_err = NULL;
> 
>     foop = new_foo(arg, &local_err);
>     if (local_err) {
>         error_propagate(errp, local_err);
>         // rely on postcondition !foop (else we'd leak it here)
>         return;
>     }
> 
> Checking the function value:
> 
>     Error *local_err = NULL;
> 
>     foop = new_foo(arg, &local_err);
>     if (!foop) {
>         error_propagate(errp, local_err);
>         return;
>     }
>     // rely on postcondition !local_err (else, we'd leak it here)
> 
> No matter which of the two you check, you rely on new_foo()'s
> postcondition "either value or *errp is null".
> 
> Therefore, switching from one to the other does not make the code more
> robust.
> 
> Checking the function value can be simplified to just
> 
>     foop = new_foo(arg, errp);
>     if (!foop) {
>         return;
>     }
> 
> I use this whenever possible, because it's simpler, and less clutter.
> 
> What you fixed is a different, less common case: a function returning a
> list on success, null on failure, where the empty list is represented as
> null.  Because a null value can be legitimately returned both on success
> and on failure, you need to examine *errp to tell the to apart.  The
> code you fixed didn't.
> 
Great! Thanks a lot!

V2 will be posted shortly!

BTW, I will include this patch in my usb patch series (usb-bus: convert init to 
realize).

Best regards,
-Gonglei

> >> scsi_hot_add() in pci-hotplug-old.c also loses the error message.  Would
> >> you care to fix that, too?
> >
> > I have noticed that, but because scsi_hot_add() pass NULL to
> > scsi_bus_legacy_add_drive(), so I let it pass. As you remainder,
> > I will post another patch to fix it. Thanks!
> 
> Appreciated!



reply via email to

[Prev in Thread] Current Thread [Next in Thread]