|
|
Subscribe / Log in / New account

Zero is a number just like any other number

Zero is a number just like any other number

Posted Oct 24, 2024 19:26 UTC (Thu) by jem (subscriber, #24231)
Parent article: realloc() and the oversize importance of zero-size objects

I don't understand why a size of zero should be a special case. Realloc can enlarge or shrink the allocated block, and you can call realloc with a pointer returned by realloc. The size of the (re)allocated block is in most cases the result of a computation. If a size of zero has a different meaning, then you have add a check for it in the caller and handle it differently.

>His opinion, expressed in unambiguous terms, was that realloc() should behave in the same way as malloc() when passed a size of zero; it should, in other words, free the passed-in object and return a pointer to a zero-byte object.

In my opinion, realloc(ptr, 0) should logically behave in the same way as realloc(ptr, 1), except that in the second case there is a single byte left instead of zero bytes.

If malloc can take a size argument of zero, returning an object with a zero sized block that can be realloc'd, why do we have the asymmetry that a realloc(ptr, 0) can't return a zero sized block (that could be realloc'd back to some larger size)?

Using realloc(ptr, 0) as a substitute for free is an ugly hack. We already have the free function.


to post comments

Zero is a number just like any other number

Posted Oct 25, 2024 7:47 UTC (Fri) by taladar (subscriber, #68407) [Link] (11 responses)

Agreed. The existing behavior where realloc acts like free also means that the lifetime of the actual pointer ends prematurely which is a special case that I bet isn't checked, especially not in the cases where the size is the result of a calculation and realloc is called on 0 sized results anyway.

Zero is a number just like any other number

Posted Oct 25, 2024 9:53 UTC (Fri) by Wol (subscriber, #4433) [Link] (7 responses)

> The existing behavior where realloc acts like free also means that the lifetime of the actual pointer ends prematurely

But the behaviour of free is that the lifetime of the pointer outlives what it's pointing to ...

(And I don't understand your argument - realloc will destroy the contents then the assignment destroys the pointer - how is post-hoc destruction premature?)

"ptr = realloc(ptr, 0)" is the only syntax where the destruction both of the pointer, and its contents, APPEARS to be atomic from the PoV of the caller.

Otherwise it's multiple operations which can get forgotten, separated, {}-errored, etc etc.

Cheers,
Wol

Zero is a number just like any other number

Posted Oct 25, 2024 10:05 UTC (Fri) by mb (subscriber, #50428) [Link] (6 responses)

Only because you write multiple operations (realloc + pointer overwriting) in the same line doesn't make them less dividable by accident.

And the pattern ptr = realloc(ptr, ...) is dangerous (memory leaks), if your size can be non-zero. This pattern should not be encouraged.

The real solution is to avoid using C altogether and switch to a sane language with a sane allocator.

Zero is a number just like any other number

Posted Oct 25, 2024 11:12 UTC (Fri) by Wol (subscriber, #4433) [Link] (4 responses)

> Only because you write multiple operations (realloc + pointer overwriting) in the same line doesn't make them less dividable by accident.

How do you chop an atomic statement in half?

> And the pattern ptr = realloc(ptr, ...) is dangerous (memory leaks), if your size can be non-zero. This pattern should not be encouraged.

You should not encourage the CORRECT use of realloc? You should know whether you want to re-use ptr or not, and you should know what sort of object you're going to put there - if the answer is "nothing" then allocate zero space. You're advocating careless programming ... you'll say I'm exaggerating, but taking your argument to its extreme it sounds like "don't bother freeing ptr, you don't know if you're going to re-use it", which is probably worse on the memory leak front ...

> The real solution is to avoid using C altogether and switch to a sane language with a sane allocator.

Agreed :-)

Zero is a number just like any other number

Posted Oct 25, 2024 12:00 UTC (Fri) by khim (subscriber, #9252) [Link]

> How do you chop an atomic statement in half?

Easy: p = realloc(q, 0);. Bam: your pointer is no longer clobbered and can be happily reused.

That approach was even tried in Go (where proper way to append something to the slice is s = append(s, t); and not just simply append(s, t); or s.append(t);) and causes nothing but grief.

> You should not encourage the CORRECT use of realloc?

It would have been “correct” if it was taught that way from the beginning (preferably in first edition of K&R).

But, alas, in our world that haven't happened, thus it falls fully into “very non-standard and unusual non-portable code that some weirdos try to promote for no good reason”.

Typical C programmer, in today's world, wouldn't even know that ptr = realloc(ptr, 0); is supposed to free memory and would look, in vain, for free, which would lead not to greater safety, but to greater confusion.

> You should know whether you want to re-use ptr or not

And you shouldn't do any other mistakes too. Which means that such code is useless for real programmers who are not taught to use it and it's also useless for imaginary “perfect” programmers who never do mistakes. Who could benefit from it, then?

> You're advocating careless programming

Nope. He (and me, too) advocate familiar programming that's based on the tools that we have today.

You are imagining some alternate world, where C is different, C programmers are different and realloc is different, too!

Sorry, but it's really too late to push for some new C and new set of C programmers and new C standard library that could, collectively, embrace that “brave new way” of dealing with memory allocations.

Zero is a number just like any other number

Posted Oct 25, 2024 12:40 UTC (Fri) by mb (subscriber, #50428) [Link] (2 responses)

> How do you chop an atomic statement in half?

It's not atomic.

> You should not encourage the CORRECT use of realloc?

No. It's usually incorrect to overwrite the pointer with the return value of realloc before checking for NULL return. If realloc fails to allocate, it does not free the pointer and returns NULL. If you overwrite your only pointer with the NULL return, you have leaked the original allocation.

Zero is a number just like any other number

Posted Oct 25, 2024 18:27 UTC (Fri) by khim (subscriber, #9252) [Link] (1 responses)

> If you overwrite your only pointer with the NULL return, you have leaked the original allocation.

Sure, but if you want not to allocate memory, but to free it and that fails… what are the mitigations? At this point I would assume that allocator would just stop the program because it's probably the best response that it could do.

And in some alternate reality where this behavior is mandated… and realloc was required to behave like that… and all C courses would have teached you to use that ability… yes, in such a world, use of realloc would have been justified.

I would argue that even in that world it would have been bad design, but familiarity of the pattern would have made it justifiable.

But inventing and pushing new convention like that in our world? That's just… I don't even know strong enough words to describe what I think about that idea.

Zero is a number just like any other number

Posted Oct 25, 2024 18:30 UTC (Fri) by mb (subscriber, #50428) [Link]

>but if you want not to allocate memory, but to free it and that fails

I commented on something else.

I was just saying that ptr = realloc(ptr, ...) was a bad pattern, because it's wrong for all cases *except* the free/zero case (maybe; implementation defined; if not UB).

Zero is a number just like any other number

Posted Oct 31, 2024 5:33 UTC (Thu) by milesrout (subscriber, #126894) [Link]

there is no rule that you have to use malloc when you write C. Plenty of people use "sane" allocators in C.

this has nothing to do with the fact p = realloc(p,...) is erroneous. Of course it is wrong! It is obviously nonsensical rubbish code with any allocator. If you cant get this basic stuff right then i dont think a "sane" allocator would save you from writing hundreds of other serious bugs in your program

Zero is a number just like any other number

Posted Oct 25, 2024 10:12 UTC (Fri) by khim (subscriber, #9252) [Link] (2 responses)

> The existing behavior where realloc acts like free also means that the lifetime of the actual pointer ends prematurely which is a special case that I bet isn't checked

After call to realloc pointer is no longer usable in all cases, I don't see where do you see the special case.

Zero is a number just like any other number

Posted Oct 25, 2024 11:04 UTC (Fri) by Wol (subscriber, #4433) [Link] (1 responses)

The "special case" is called "use after free".

main {
void *ptr;
ptrr = malloc(6);
free(ptr);
*ptr = 9.6;
}

My C is rusty, but that will access what ptr USED TO point at, and (possibly) do a load of damage?

Whereas
ptr = realloc(ptr, 0);
using the "returns null" definition will in most circumstances trap and cause a run-time error "dereferencing null pointer"?

The point is that, from the PoV of the calling function, realloc ATOMICally destroys BOTH what is pointed at, and what is doing the pointing. Absent multiple copies, you don't get dangling pointers lying around to cause "use after free" problems.

And it's easily enforced with a couple of rules, that I guess are easy to write in a linter - "don't use free; never ignore the return from realloc".

Cheers,
Wol

Zero is a number just like any other number

Posted Oct 25, 2024 11:43 UTC (Fri) by khim (subscriber, #9252) [Link]

> using the "returns null" definition will in most circumstances trap and cause a run-time error "dereferencing null pointer"?

It may or may not do that. In fact in a world where *ptr = 9.6; means I solemnly swear that ptr is not NULL and ptr = realloc(ptr, 0); means I solemnly swear that ptr would be NULL this could be “interpreted” by the compiler in a very radical manner with very non-obvious consequences.

> And it's easily enforced with a couple of rules, that I guess are easy to write in a linter - "don't use free; never ignore the return from realloc".

Which is still much more convoluted and contrived way that just “use FREE macro” that is defined as ({typeof(&p) addr_of_p = &p; free(*addr_of_p); *addr_of_p = NULL;}).

I agree that in some alternate reality where C would have developed in some other direction than how it happened in our world realloc used in this fashion can aid safety, but in the mess that we have now, today? Nope, it would just make everything worse.

Note that free is already defined as function that invalidates pointer and compiler can be taught to detect these situations statically in simple cases while in more complicated cases use-after-free comes not from pointer directly passed to free but from entirely different pointer stashed in some different struct.

Zero is a number just like any other number

Posted Oct 25, 2024 8:08 UTC (Fri) by Wol (subscriber, #4433) [Link] (1 responses)

> Using realloc(ptr, 0) as a substitute for free is an ugly hack. We already have the free function.

But they're not identical. realloc is a function, free is a subroutine. From the point of view of the caller, wiping the pointer with realloc is an atomic operation, freeing then wiping is two actions which could get separated (or forgotten).

So what if realloc is a hack. It's also an aid to memory safety, and probably far easier to lint.

Cheers,
Wol

Zero is a number just like any other number

Posted Oct 25, 2024 10:31 UTC (Fri) by khim (subscriber, #9252) [Link]

> It's also an aid to memory safety

As it's currently defined it's far from an aid to anything. Notice how it invalides some pointers that are not even arguments to realloc!

> and probably far easier to lint

The simples rule to enforce: flag any use of realloc and ask developer to stop doing it. Presto: problem solved.

It may not be the most satisfying solution and in some alternate world realloc would behave differently but after the mess that was already created around it any attempt to use it for safety is a fools errand.

You may never make different people agree on how these realloc-using programs have to behave.

From safety POV the simplest resolution that hyphotetical C50 may do is to just replace all that mess with call to realloc is undefined behavior. That would be shorter, simpler… and wouldn't affect all that many programs, in reality.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds