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
next prev parent 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).