C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Delete...why not a parameter by reference?!

From: Oliver Hunt <oliver_at_[hidden]>
Date: Fri, 22 Aug 2025 22:13:17 -0700
> On Aug 22, 2025, at 8:04 PM, organicoman via Std-Proposals <std-proposals_at_[hidden]> wrote:
>
> Hello,
> One of the recurring bugs in c++ is use after free.
> I'm wondering, why the delete operator doesn't take the pointer parameter by reference and nullify it?
> So instead of
> void operator delete(void* p);
> It becomes
> void operator delete(void* &p);
> And it assigns the value nullptr to p after freeing its corresponding memory.

Use after free errors are very seldom a direct case of

  delete some_ptr;
  use(some_ptr);

They are almost always

some_ptr = …


Somewhere else
delete something;


Where something may be a pointer to the same address, or it may be an object with a destructor that transitively releases the the pointer referenced by some_ptr.

Later on in some other location:
use(some_ptr)

Zeroing out one single pointer does nothing for the other cases, and almost all analysis tools can identify trivial use after free, and I believe


> Look at this example:
> ---------
> {
> int* p = new int(42);
> int* const& to_p = p; // as a guideline
> delete p; // if taken by reference an nullified
> *p; // this will be a guaranteed runtime error
> *to_p; // and all previous copies obey too

You can’t do this last bit because you do not know where those references are.


> }
> ---------
> On top of that, basically we need just to add a guideline that mandate:
> -All duplication of a pointer should be by reference if modifying, or const reference if not.

Doing this would require allocating memory to hold the reference, and then having some way to manage the lifetime of that reference. At this point you have replaced raw pointers with handles, but handles have the same lifetime difficulties of the original pointer.

> So it is guaranteed that if you free the memory using any of the references, all copies will be nullptr.
>
> So, is there any constraints to prevents this other than breaking old code?


Fundamentally it does not work. Assuming that you are able to break older code, and take the performance and memory cost, you now need to ensure appropriate lifetime of the handle object, because those need to be allocated and released, and to handle |this| you need to be able to go from an arbitrary pointer back to a handle. Then to handle |this| you need to have a way to go from |this| to a handle, even though |this| may be a sub object, or other non-dynamically allocated object (stack variable, global, etc).

There is no simple fix for lifetime safety in C or C++.

—Oliver

Received on 2025-08-23 05:13:29