shap@delrey.sgi.com (Jonathan Shapiro) (03/13/90)
I believe that a small change to the definition of the delete operator is worth considering. The change would have no effect on correct programs, but would help find incorrect programs in some circumstances. delete should be defined to zero the pointer it is handed after freeing the associated store. Reasons: 1. Unlike C, C++ does not guarantee that the object is live until the next call to new. 2. In the absence of setting the pointer to zero, accesses to data items that erroneously follow the delete cannot be caught even when the hardware traps page-zero references, and compilers have not yet arrived that understand about this. 3. If the code is correct, dead code elimination in the compiler can generally be relied on to eliminate the zero set, so the run-time cost should be nil. 4. I can't think of a correct code sequence it would break. Of course, compilers should be taught to understand about use after clobber, but that's a bit harder, and I don't see how this tweak to the language spec can hurt. Jonathan Shapiro Silicon Graphics, Inc.
rfg@ics.uci.edu (Ronald Guilmette) (03/13/90)
In article <5136@odin.SGI.COM> shap@delrey.sgi.com (Jonathan Shapiro) writes: >I believe that a small change to the definition of the delete operator >is worth considering. The change would have no effect on correct >programs, but would help find incorrect programs in some circumstances. > > delete should be defined to zero the pointer it is handed > after freeing the associated store. That would be a swell idea, except that I don't believe that the value in a delete statement is required to be an lvalue. What should the compiler do if the value is *not* an lvalue? Punt? // Ron Guilmette (rfg@ics.uci.edu) // C++ Entomologist // Motto: If it sticks, force it. If it breaks, it needed replacing anyway.
sakkinen@tukki.jyu.fi (Markku Sakkinen) (03/14/90)
In article <25FC0210.26173@paris.ics.uci.edu> rfg@ics.uci.edu (Ronald Guilmette) writes: >In article <5136@odin.SGI.COM> shap@delrey.sgi.com (Jonathan Shapiro) writes: >>I believe that a small change to the definition of the delete operator >>is worth considering. The change would have no effect on correct >>programs, but would help find incorrect programs in some circumstances. >> >> delete should be defined to zero the pointer it is handed >> after freeing the associated store. > >That would be a swell idea, except that I don't believe that the value >in a delete statement is required to be an lvalue. What should the compiler >do if the value is *not* an lvalue? Punt? Right: If the delete operator is redefined for a class, then according to the C++ 2.0 Reference Manual it will be like void operator delete (void*) (possibly with a second argument). Thus it only gets a _copy_ of the pointer value. Shapiro's proposal is nevertheless sensible, and would make 'new' and 'delete' more symmetric. The zeroing could be done _if_ the operand is an lvalue. For a redefined delete operator, this could be done _before_ it is actually invoked, but after the destructor (if any) is invoked. Of course one can keep many pointers to a dynamic object, but in the majority of cases in "typical" code there is probably only one pointer to each object, and so zeroing it automatically would help a lot, e.g. prevent trivial errors. Markku Sakkinen Department of Computer Science University of Jyvaskyla (a's with umlauts) Seminaarinkatu 15 SF-40100 Jyvaskyla (umlauts again) Finland SAKKINEN@FINJYU.bitnet (alternative network address)
shap@delrey.sgi.com (Jonathan Shapiro) (03/15/90)
In article <3743@tukki.jyu.fi> sakkinen@jytko.jyu.fi (Markku Sakkinen) writes: > >Shapiro's proposal is nevertheless sensible, and would make 'new' and >'delete' more symmetric. The zeroing could be done _if_ the operand >is an lvalue. For a redefined delete operator, this could be done >_before_ it is actually invoked, but after the destructor (if any) >is invoked. All I wanted was a definition that helped debugging on many systems if it wasn't incorrect. Enough people have pointed out that rvalues make it a problem that I am forced to conclude that it isn't correct and shouldn't be part of the language definition. It might still be worth an implementation note to encourage compiler authors to generate pre-optimized code that zeroes the pointer iff it is an lvalue in the interest of debugging. Jon Shapiro Silicon Graphics
keith@csli.Stanford.EDU (Keith Nishihara) (03/15/90)
Consistency is very important. A language variant which sometimes nulls the argument to delete, and sometimes not (according to whether the argument is an lvalue), and which never zeros additional pointers to deleted objects invites errors due to misunderstanding and misuse. Bad idea! Neil/. Neil%teleos.com@ai.sri.com
jeffa@hpmwtd.HP.COM (Jeff Aguilera) (03/16/90)
> > delete should be defined to zero the pointer it is handed > after freeing the associated store. > During program testing and development, a custom allocator is often worthwhile. I use a moderately piggish allocator that remembers the caller (by walking the stack frame!!) so that memory leaks can be tracked down. The deallocator checks pointer validity, off by-one errors, and zeroes the allocated store on delete. Erroneous access to deleted pointers is normally caught right away. Since your problem is effectively solved using existing language features, may I remind you of your own arrogance: "This is a great example of why language design should be left to people who know what they're doing." You forgot your smiley :-) ----- jeffa
sharam@munnari.oz.au (Sharam Hekmatpour) (03/16/90)
From article <5136@odin.SGI.COM>, by shap@delrey.sgi.com (Jonathan Shapiro): > delete should be defined to zero the pointer it is handed > after freeing the associated store. I agree with you. A few people have pointed out that this causes problems when the operand of delete is not an lvalue. They are WRONG. Let me explain why... The case that the operand is *not* an lvalue can be handled by, for example, ensuring that a *copy* of the pointer is zeroed instead (as if no zeroing has taken place). This is perfectly safe. Using references, implementing this in C++ is very easy: inline void zelete (void*& ptr) // Zero after dELETE { delete ptr; ptr = 0; } Now suppose p and q+10 point to valid blocks created by new: zelete(p); // deletes and zeros p zelete(q+10); // deletes but does not zero q+10 In the latter case, because the formal argument is a reference, the actual argument is treated as a value; hence ptr receives a *copy* of q+10 and zeros that! So non-lvalues are treated properly. Aside, it is a shame that this cannot be achieved by globally overloading delete, since we will end up with infinite recursion. Defining it as a function having a different name (as I've done here) is just about the neatest way I can think of right now. Regards, Sharam Hekmatpour
ark@alice.UUCP (Andrew Koenig) (03/17/90)
In article <5136@odin.SGI.COM>, shap@delrey.sgi.com (Jonathan Shapiro) writes: > I believe that a small change to the definition of the delete operator > is worth considering. The change would have no effect on correct > programs, but would help find incorrect programs in some circumstances. > delete should be defined to zero the pointer it is handed > after freeing the associated store. But the pointer might not be an lvalue! In any event, if you look at the latest C++ reference manual, you will find that the implementation is permitted (but not obliged) to zero the pointer that is the subject of `delete.' It is not obliged to do so in case some people don't want to live with the small amount of additional overhead implied. -- --Andrew Koenig ark@europa.att.com
rfg@ics.uci.edu (Ronald Guilmette) (03/18/90)
In article <5263@odin.SGI.COM> shap@delrey.sgi.com (Jonathan Shapiro) writes: >In article <3743@tukki.jyu.fi> sakkinen@jytko.jyu.fi (Markku Sakkinen) writes: >> >>Shapiro's proposal is nevertheless sensible, and would make 'new' and >>'delete' more symmetric. The zeroing could be done _if_ the operand >>is an lvalue. For a redefined delete operator, this could be done >>_before_ it is actually invoked, but after the destructor (if any) >>is invoked. > >All I wanted was a definition that helped debugging on many systems if >it wasn't incorrect. Enough people have pointed out that rvalues make >it a problem that I am forced to conclude that it isn't correct and >shouldn't be part of the language definition. > >It might still be worth an implementation note to encourage compiler >authors to generate pre-optimized code that zeroes the pointer iff it >is an lvalue in the interest of debugging. Now I think that you are on to a very good idea here! It would certainly be nice if the language definition were to say that: "In cases where the expression given in a delete statement is an lvalue, the value of that lvalue after the execution of the delete statement is undefined." A rule like that would allow (but not require) the zeroing of lvalue pointers given in delete statements. Implementors could then choose if they wanted to do the zeroing for the sake of slightly better debugability. // Ron Guilmette (rfg@ics.uci.edu) // C++ Entomologist // Motto: If it sticks, force it. If it breaks, it needed replacing anyway.
psrc@pegasus.ATT.COM (Paul S. R. Chisholm) (03/19/90)
<Krasny Oktyabr: "The torpedo has acquisition!" That's the good news?> In article <5263@odin.SGI.COM> shap@delrey.sgi.com (Jonathan Shapiro) suggests that "delete p" should set the value of p to a null pointer after the memory it points at is free. Later posters suggest that the pointer may not be an lvalue. I haven't seen anyone suggest a decent example where a non-lvalue *should* be passed to delete, and I have a strong gut feeling that such an expression should probably generate a warning! But anyway, if it's an lvalue, yes, I agree, implementors should be free to zero out the pointer. (Or not, if the application is *so* time critical that the assignment might slow things down. We all know how expensive assignment is as compared to memory deallocation, right?-) Leaving the value alone may also help debugging. In article <260349F1.24972@paris.ics.uci.edu>, rfg@ics.uci.edu (Ronald Guilmette) agrees, writing: > It would certainly be nice if the language definition were to say that: > "In cases where the expression given in a delete statement is an lvalue, > the value of that lvalue after the execution of the delete statement is > undefined." Well, open your ugly red book ("UNIX(R) System V AT&T C++ Language System, Release 2.0, Product Reference Manual", select code 307-146) to page 20, and repeat after me: "if the expression denoting the object in a delete expression is a modifiable lvalue its value is undefined after the deletion." Well, it's good to know Dr. Stroustrup agrees with us. . . .-) > // Ron Guilmette (rfg@ics.uci.edu) Paul S. R. Chisholm, AT&T Bell Laboratories att!pegasus!psrc, psrc@pegasus.att.com, AT&T Mail !psrchisholm I'm not speaking for the company, I'm just speaking my mind. UNIX(R) is a registered trademark of AT&T. P.S.: How does one have an unmodifiable lvalue? By using the const keyword, of course. I'd like a warning there, too.