Date: Mon, 25 Aug 2025 03:13:50 +0100
Hi,I'm really surprised about how it is difficult to some people to understand this proposal. This will be my last take.------------Intro:C++ as language guarantee backward compatibility and support for very old code. This has been said, it means that there is so many lines of code, out there, still using raw pointers. For those code bases, I want to propose a way to catch bugs with very minimal change.Agreement:1- I'm not trying to downgrade the usage of smart pointers compain, so if there is any mean to switch to smart pointers, then go for it.2- I'm not talking about containers, or how to store references.Take the proposal as is, no extrapolation.The problem:The problem is illustrated with the following code snippet. 1. {2. T* ptr = new T{....}; // T well defined type3. Foo(ptr); // opaque callee4. // this line: see discussion below5. }Explanation:On line 2, I allocate a memory resource to store a variable of type T. T is a type defined in previous code.On line 3, I call a function 'Foo', which has the following signature:void Foo(T*);This function comes from a closed source code, so there is no way that I can analyze its code.But, when I read its documentation, I find the following scenario (each scenario will be discussed separately)1- case: the documentation promises that the consumed pointer will not be deleted (not owning function)******* but the function has a bug*******As a user of that function, I take that doc as true, and in line 4 above, I can follow up with this code.4. delete ptr; // (A)Or4. *ptr = T{...}; // (B)The buggy function in actuality, does break its contract by mistake and free the resource owned by 'ptr'Because of that, I can fall in 2 bugs, extremely difficult to catch.(A) double free(B) use after free2- case: the documentation of the function, guarantees that the pointer is owned and delete was called on it.****** yet the function is buggy******Because of the documentation again, I can follow up with this code4. ptr = new T{....}; // (C)The function in reality doesn't free the resource by mistake, which induces me in error, and make me fall in another category of bugs called memory leak (C)All of the bugs above encounter in the function 'Foo' are unintentional. The proposal:To help detect this kind of mistakes, I propose the following correction to the delete expression signature Previous signature:void delete(void*);Become:void delete (void* &);Also to help this change takes a full effect on catching the 3 categories of bugs above, I like to add the following guide line with the proposal:It would be optional, but extremely useful, to make any callee take the argument per a reference to pointer, so if your callee signature is as follow:RetType fnName(T*); Change it to:RetType fnName(T* &);Proposal cost:Changing the delete expression signature, won't affect the calling code. So there is no source code change, no grep and modify or any type of code breakage.Following the guidline suggested above, will affect only the header files, included by the consuming source code.ABI wise, hopefully there is a way, at compilers implementers level, to not break the ABI, this is based on the assumption that, previously the delete expression has undefined behaviour when passed a nullptr, but nowadays it handles the nullptr correctly, this change was done without breaking any ABI.If done once, I hope that It can be done twice. Conclusion:The proposal doesn't bash actual or future replacement for using raw pointers, but to reach the top floor of security, we need to climbe the stairs, one stair a time.
Received on 2025-08-25 02:13:57