Anthony Liguori <anth...@codemonkey.ws> writes: > Avi Kivity wrote: >> On 12/04/2009 06:49 PM, Anthony Liguori wrote: >>> >>> I still believe that it is poor practice to pass size==0 to >>> *malloc(). I think actively discouraging this in qemu is a good >>> thing because it's a broken idiom. >> >> Why? Unless we have a separate array allocator (like C++'s new and >> new[]), we need to support zero-element arrays without pushing the >> burden to callers (in the same way that for () supports zero >> iteration loops without a separate if ()). > > If you call malloc(size=0), then it's impossible to differentiate > between a failed malloc return and a valid result on certain platform > (like AIX). > > So the only correct way would be to write: > > array = malloc(size); > if (array == NULL && size != 0) { > return -ENOMEM; > } > > If you were writing portable code. But that's not what people write.
Yup. But if (n == 0) p = malloc(n * sizeof(struct foo)) else p = NULL; isn't what people write either. > You can argue that qemu_malloc() can have any semantics we want and > while that's true, it doesn't change my above statement. I think the > main argument for this behavior in qemu is that people are used to > using this idiom with malloc() but it's a non-portable practice. We've decided long ago to disable the trap you quoted by not returning NULL for empty allocations. That way it doesn't kill us when people fail to call qemu_malloc() perfectly every time. > If qemu_malloc() didn't carry the name "malloc()" then semantics with > size=0 would be a different discussion. But so far, all qemu_* > functions tend to behave almost exactly like their C counterparts. That's a reason for making qemu_malloc() work for zero arguments, because its C counterpart does. > Relying on the result of size=0 with malloc() is broken. No. Relying on non-null-ness is broken. You can write perfectly portable, working code without doing that. p = malloc(n * sizeof(struct foo); if (n && !p) exit_no_mem(); for (i = 0; i < n; i++) compute_one(p, i); With qemu_malloc(), the error handling moves into qemu_malloc(): p = qemu_malloc(n * sizeof(struct foo); for (i = 0; i < n; i++) compute_one(p, i);