qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: malc <av1474@comtv.ru>
To: Markus Armbruster <armbru@redhat.com>
Cc: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH] Permit zero-sized qemu_malloc() & friends
Date: Mon, 7 Dec 2009 19:55:04 +0300 (MSK)	[thread overview]
Message-ID: <Pine.LNX.4.64.0912071939580.2225@linmac.oyster.ru> (raw)
In-Reply-To: <m3638ilu5v.fsf@crossbow.pond.sub.org>

On Mon, 7 Dec 2009, Markus Armbruster wrote:

> malc <av1474@comtv.ru> writes:
> 
> > On Mon, 30 Nov 2009, Markus Armbruster wrote:
> >
> >> Commit a7d27b53 made zero-sized allocations a fatal error, deviating
> >> from ISO C's malloc() & friends.  Revert that, but take care never to
> >> return a null pointer, like malloc() & friends may do (it's
> >> implementation defined), because that's another source of bugs.
> >> 
> >> Rationale: while zero-sized allocations might occasionally be a sign of
> >> something going wrong, they can also be perfectly legitimate.  The
> >> change broke such legitimate uses.  We've found and "fixed" at least one
> >> of them already (commit eb0b64f7, also reverted by this patch), and
> >> another one just popped up: the change broke qcow2 images with virtual
> >> disk size zero, i.e. images that don't hold real data but only VM state
> >> of snapshots.
> >> 
> >> If a change breaks two uses, it probably breaks more.  As a quick check,
> >> I reviewed the first six of more than 200 uses of qemu_mallocz(),
> >> qemu_malloc() and qemu_realloc() that don't have an argument of the form
> >> sizeof(...) or similar:
> >
> > Bottom line: your point is that there are benign uses of zero allocation.
> > There are, at the expense of memory consumption/fragmentation and useless
> > code which, as your investigation shows, involve syscalls and what not.
> 
> I doubt the performance impact is relevant, but since you insist on
> discussing it...
> 
> First and foremost, any performance argument not backed by measurements
> is speculative.
> 
> Potential zero allocation is common in code.  Actual zero allocation is
> rare at runtime.  The amount of memory consumed is therefore utterly
> trivial compared to total dynamic memory use.  Likewise, time spent in
> allocating is dwarved by time spent in other invocations of malloc()
> several times over.
> 
> Adding a special case for avoiding zero allocation is not free.  Unless
> zero allocations are sufficiently frequent, that cost exceeds the cost
> of the rare zero allocation.

I bet you dollars to donuts that testing for zero before calling malloc
is cheaper than the eventual test that is done inside it.

> 
> > Outlook from my side of the fence: no one audited the code, no one
> > knows that all of the uses are benign, abort gives the best automatic
> > way to know for sure one way or the other.
> >
> > Rationale for keeping it as is: zero-sized allocations - overwhelming
> > majority of the times, are not anticipated and not well understood,
> > aborting gives us the ability to eliminate them in an automatic
> > fashion.
> 
> Keeping it as is releasing with known crash bugs, and a known pattern
> for unknown crash bugs.  Is that what you want us to do?  I doubt it.

Yes, it's better than having _silent_ bugs, which, furthermore, have a
good potential of mainfesting themselves a lot further from the "bug"
site.

> 
> I grant you that there may be allocations we expect never to be empty,
> and where things break when they are.  Would you concede that there are
> allocations that work just fine when empty?

I wont dispute that.

> 
> If you do, we end up with three kinds of allocations: known empty bad,
> known empty fine, unknown.  Aborting on known empty bad is okay with me.
> Aborting on unknown in developement builds is okay with me, too.  I
> don't expect it to be a successful way to find bugs, because empty
> allocations are rare.
> 
> Initially, all allocations should be treated as "unknown".  I want a way
> to mark an allocation as "known empty fine".  I figure you want a way to
> mark "known empty bad".
> 
> >> * load_elf32(), load_elf64() in hw/elf_ops.h:
> >> 
> >>     size = ehdr.e_phnum * sizeof(phdr[0]);
> >>     lseek(fd, ehdr.e_phoff, SEEK_SET);
> >>     phdr = qemu_mallocz(size);
> >> 
> >>   This aborts when the ELF file has no program header table, because
> >>   then e_phnum is zero (TIS ELF 1.2 page 1-6).  Even if we require the
> >>   ELF file to have a program header table, aborting is not an acceptable
> >>   way to reject an unsuitable or malformed ELF file.
> >
> > If there's a malformed ELF files that must be supported (and by supported
> > - user notification is meant) then things should be checked, because having
> > gargantuan size will force qemu_mallocz to abort via OOM check (even
> > with Linux and overcommit, since malloc will fallback to mmap which
> > will fail) and this argument falls apart.
> 
> ELF files with empty PHT are *not* malformed.  Empty PHT is explicitly
> permitted by ELF TIS.  Likewise for empty segments.  I already gave you
> chapter & verse.

Uh, it's you who brought the whole malformed issue.

> 
> >> * load_elf32(), load_elf64() in hw/elf_ops.h:
> >> 
> >>             mem_size = ph->p_memsz;
> >>             /* XXX: avoid allocating */
> >>             data = qemu_mallocz(mem_size);
> >> 
> >>   This aborts when the segment occupies zero bytes in the image file
> >>   (TIS ELF 1.2 page 2-2).
> >> 
> >> * bdrv_open2() in block.c:
> >> 
> >>     bs->opaque = qemu_mallocz(drv->instance_size);
> >> 
> >>   However, vvfat_write_target.instance_size is zero.  Not sure whether
> >>   this actually bites or is "only" a time bomb.
> >> 
> >> * qemu_aio_get() in block.c:
> >> 
> >>         acb = qemu_mallocz(pool->aiocb_size);
> >> 
> >>   No existing instance of BlockDriverAIOCB has a zero aiocb_size.
> >>   Probably okay.
> >> 
> >> * defaultallocator_create_displaysurface() in console.c has
> >> 
> >>     surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
> >> 
> >>   With Xen, surface->linesize and surface->height come out of
> >>   xenfb_configure_fb(), which set xenfb->width and xenfb->height to
> >>   values obtained from the guest.  If a buggy guest sets one to zero, we
> >>   abort.  Not an good way to handle that.
> >
> > What is? Let's suppose height is zero, without explicit checks, user
> > will never know why his screen doesn't update, with abort he will at
> > least know that something is very wrong.
> 
> My point isn't that permitting malloc(0) is the best way to handle it.
> It's a better way than aborting, though.

And this is precisely the gist of our disagreement.

> 
> I'm not arguing against treating case 0 specially ever.
> 
> >>   Non-Xen uses aren't obviously correct either, but I didn't dig deeper.
> >> 
> >> * load_device_tree() in device_tree.c:
> >> 
> >>     *sizep = 0;
> >>     dt_size = get_image_size(filename_path);
> >>     if (dt_size < 0) {
> >>         printf("Unable to get size of device tree file '%s'\n",
> >>             filename_path);
> >>         goto fail;
> >>     }
> >> 
> >>     /* Expand to 2x size to give enough room for manipulation.  */
> >>     dt_size *= 2;
> >>     /* First allocate space in qemu for device tree */
> >>     fdt = qemu_mallocz(dt_size);
> >> 
> >>   We abort if the image is empty.  Not an acceptable way to handle that.
> >> 
> >> Based on this sample, I'm confident there are many more uses broken by
> >> the change.
> >
> > Based on this sample i'm confident, we can eventually fix them should those
> > become the problem.
> 
> You broke working code.  I'm glad you're confident we can fix it
> "eventually".  What about 0.12?  Ship it broken?

I'm fixing those as they arrive.

> 
> >> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> >> ---
> >>  block/qcow2-snapshot.c |    5 -----
> >>  qemu-malloc.c          |   14 ++------------
> >>  2 files changed, 2 insertions(+), 17 deletions(-)
> >> 
> >> diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
> >> index 94cb838..e3b208c 100644
> >> --- a/block/qcow2-snapshot.c
> >> +++ b/block/qcow2-snapshot.c
> >> @@ -381,11 +381,6 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
> >>      QCowSnapshot *sn;
> >>      int i;
> >>  
> >> -    if (!s->nb_snapshots) {
> >> -        *psn_tab = NULL;
> >> -        return s->nb_snapshots;
> >> -    }
> >> -
> >>      sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
> >>      for(i = 0; i < s->nb_snapshots; i++) {
> >>          sn_info = sn_tab + i;
> >> diff --git a/qemu-malloc.c b/qemu-malloc.c
> >> index 295d185..aeeb78b 100644
> >> --- a/qemu-malloc.c
> >> +++ b/qemu-malloc.c
> >> @@ -44,22 +44,12 @@ void qemu_free(void *ptr)
> >>  
> >>  void *qemu_malloc(size_t size)
> >>  {
> >> -    if (!size) {
> >> -        abort();
> >> -    }
> >> -    return oom_check(malloc(size));
> >> +    return oom_check(malloc(size ? size : 1));
> >>  }
> >>  
> >>  void *qemu_realloc(void *ptr, size_t size)
> >>  {
> >> -    if (size) {
> >> -        return oom_check(realloc(ptr, size));
> >> -    } else {
> >> -        if (ptr) {
> >> -            return realloc(ptr, size);
> >> -        }
> >> -    }
> >> -    abort();
> >> +    return oom_check(realloc(ptr, size ? size : 1));
> >>  }
> >
> > http://groups.google.com/group/comp.std.c/browse_thread/thread/4e9af8847613d71f/6f75ad22e0768a0b?q=realloc++group:comp.std.c#6f75ad22e0768a0b
> 
> --verbose ?

Sigh...

C90 - realloc(non-null, 0) =
      free(non-null); return NULL;

C99 - realloc(non-null, 0) =
      free(non-null); return realloc(NULL, 0); 

GLIBC 2.7 = C90

How anyone can use this interface and it's implementations portably
or "sanely" is beyond me.

Do read the discussion the linked above.

-- 
mailto:av1474@comtv.ru

  reply	other threads:[~2009-12-07 16:55 UTC|newest]

Thread overview: 119+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-11-30 13:55 [Qemu-devel] [PATCH] Permit zero-sized qemu_malloc() & friends Markus Armbruster
2009-11-30 14:01 ` Avi Kivity
2009-11-30 14:23 ` Kevin Wolf
2009-12-01 12:40 ` Gerd Hoffmann
2009-12-01 12:57   ` Paul Brook
2009-12-01 13:47     ` Glauber Costa
2009-12-01 14:08       ` Markus Armbruster
2009-12-01 14:47         ` Gerd Hoffmann
2009-12-01 14:21       ` Paul Brook
2009-12-01 12:57   ` Gerd Hoffmann
2009-12-01 13:11   ` Markus Armbruster
2009-12-01 14:34   ` Avi Kivity
2009-12-01 14:53     ` Gerd Hoffmann
2009-12-01 15:32 ` Eduardo Habkost
2009-12-04 16:49 ` Anthony Liguori
2009-12-05 13:55   ` Markus Armbruster
2009-12-05 14:14     ` Laurent Desnogues
2009-12-05 17:08     ` malc
2009-12-05 17:23       ` Avi Kivity
2009-12-05 18:30       ` Reimar Döffinger
2009-12-06  7:57       ` Markus Armbruster
2009-12-06  8:39         ` malc
2009-12-06  8:59           ` Markus Armbruster
2009-12-06 10:22             ` malc
2009-12-06 10:40               ` Avi Kivity
2009-12-06 11:53                 ` malc
2009-12-06 12:07                   ` Avi Kivity
2009-12-06 12:11                     ` malc
2009-12-06 12:23                       ` Avi Kivity
2009-12-06 11:10               ` Markus Armbruster
2009-12-06 12:00                 ` malc
2009-12-06 16:23                   ` [Qemu-devel] " Paolo Bonzini
2009-12-07  8:35                   ` [Qemu-devel] " Kevin Wolf
2009-12-07  9:42                   ` Markus Armbruster
2009-12-07 10:00                     ` malc
2009-12-07 10:17                       ` Kevin Wolf
2009-12-07 10:35                       ` Markus Armbruster
2009-12-06 11:35               ` [Qemu-devel] " Paolo Bonzini
2009-12-06 12:02                 ` malc
2009-12-06 16:23                   ` Paolo Bonzini
2009-12-06  9:02           ` [Qemu-devel] " Blue Swirl
2009-12-06 10:02             ` malc
2009-12-05 17:07   ` Avi Kivity
2009-12-05 17:27     ` Anthony Liguori
2009-12-05 17:40       ` Avi Kivity
2009-12-05 17:54         ` Anthony Liguori
2009-12-05 18:06           ` Avi Kivity
2009-12-05 20:58             ` Anthony Liguori
2009-12-05 22:26               ` Avi Kivity
2009-12-06  8:24                 ` Markus Armbruster
2009-12-06 18:36                 ` Jamie Lokier
2009-12-06  8:12       ` Markus Armbruster
2009-12-06 16:52         ` Ian Molton
2009-12-06 17:14           ` Avi Kivity
2009-12-06 17:45             ` malc
2009-12-06 18:02               ` Avi Kivity
2009-12-06 18:12                 ` malc
2009-12-06 18:19                   ` Avi Kivity
2009-12-06 18:41                     ` malc
2009-12-07  9:47                       ` Avi Kivity
2009-12-07 10:20                         ` Kevin Wolf
2009-12-06 22:38                 ` Ian Molton
2009-12-07  2:51                   ` Jamie Lokier
2009-12-07  9:39                     ` Ian Molton
2009-12-07  9:55                       ` [Qemu-devel] " Paolo Bonzini
2009-12-07 13:28                         ` Avi Kivity
2009-12-07  9:45           ` [Qemu-devel] " Markus Armbruster
2009-12-07  8:48       ` Kevin Wolf
2009-12-07 17:32       ` Glauber Costa
2009-12-05 17:28     ` Blue Swirl
2009-12-05 17:44       ` Avi Kivity
2009-12-05 18:16         ` Laurent Desnogues
2009-12-05 23:08         ` Ian Molton
2009-12-05 23:11           ` Avi Kivity
2009-12-05 23:25             ` Ian Molton
2009-12-06 13:07               ` Avi Kivity
2009-12-06 16:58                 ` Ian Molton
2009-12-06 17:07                   ` Avi Kivity
2009-12-06 17:47                     ` malc
2009-12-06 17:59                       ` Avi Kivity
2009-12-06 18:09                         ` malc
2009-12-06 18:16                           ` Avi Kivity
2009-12-06 18:21                             ` malc
2009-12-06 22:40                           ` Ian Molton
2009-12-06 18:31               ` Jamie Lokier
2009-12-07  9:56                 ` Markus Armbruster
2009-12-07 11:30 ` malc
2009-12-07 14:45   ` Markus Armbruster
2009-12-07 16:55     ` malc [this message]
2009-12-08  8:21       ` Markus Armbruster
2009-12-08 10:22         ` malc
2009-12-07 15:50 ` Anthony Liguori
2009-12-07 16:00   ` Avi Kivity
2009-12-07 16:06     ` Anthony Liguori
2009-12-07 16:11       ` Avi Kivity
2009-12-07 16:20         ` Anthony Liguori
2009-12-07 16:26           ` Avi Kivity
2009-12-07 16:32             ` Anthony Liguori
2009-12-07 16:37               ` Avi Kivity
2009-12-07 16:59                 ` Anthony Liguori
2009-12-07 17:07                   ` Avi Kivity
2009-12-07 17:09                     ` Anthony Liguori
2009-12-07 17:13                       ` Avi Kivity
2009-12-07 17:17                         ` Anthony Liguori
2009-12-07 17:19                           ` Avi Kivity
2009-12-07 17:40                             ` Anthony Liguori
2009-12-07 18:25                               ` Avi Kivity
2009-12-07 18:59                                 ` Anthony Liguori
2009-12-07 19:01                                   ` Avi Kivity
2009-12-07 19:07                                     ` Anthony Liguori
2009-12-07 16:24   ` Paul Brook
2009-12-07 16:27     ` Anthony Liguori
2009-12-07 16:28     ` Avi Kivity
2009-12-07 16:57   ` malc
2009-12-07 17:01     ` Anthony Liguori
2009-12-07 17:09       ` malc
2009-12-08  9:02         ` Kevin Wolf
2009-12-07 18:12   ` Blue Swirl
2009-12-08  8:30   ` 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=Pine.LNX.4.64.0912071939580.2225@linmac.oyster.ru \
    --to=av1474@comtv.ru \
    --cc=armbru@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).