Rollo62 551 Posted February 24 Thanks, its clear then, how the capture of anonymous methods work. We came from the question how FreeAndNil might be helpful here, in this kind of situations, right? Aren't there any situations where FAN can be useful, perhaps with an Assigned( FVar ) guard, were everybody can agree on? I can see much use of FAN in Delphi RTL, Spring4D and all many places all around, but at the same time everybody disagrees on its usefulness & better to avoid it, thats strange ... Where and why is it useful then, if not in situations where I want to check and mark the validity of a lazy Field or the like, for example by Assigned()? I cannot think of much use-cases, where I would ever need this. - If I use it in the case where I inject an object to a class, not by DI, but by method or property, then this would make sense to protect a Field by FAN, IMHO. - In a use case where I purely manage a Field myself by Create/Destroy, it doesn't make much sense if there is no possibility of delayed access to it. So maybe somebody has a clean example, to show where it makes sense? Share this post Link to post
Brandon Staggs 340 Posted February 24 18 minutes ago, Rollo62 said: So maybe somebody has a clean example, to show where it makes sense? If the variable is going out of scope, it doesn't make sense to nil it. If the variable is not going out of scope, then nil it. I guess the question you might ask is why you would have a reference stay in scope after it is freed. That will depend on what is being done. For example, I do this if I have a lazy-loaded class field exposed as a property that is initialized in is getter. If there is something that invalidates the reference, it needs to be nilled so that it will not be freed again when the class is freed (double-freed), and so that it can be re-initialized the next time the property is read. Share this post Link to post
Remy Lebeau 1512 Posted February 24 Sorry, I'm a little late to seeing this... 7 hours ago, Rollo62 said: Yes, but from my experience, this helps to REDUCE the risk of AV's, in case of async processes, where you cannot safely cancel such async operation, because its not directly under your control. I see it the other way - it can INCREASE the likelihood of an AV (or worse!). The callback's Self pointer will be pointing at memory which the now-dead TMyClass object was occupying. It's undefined behavior for the callback to access that memory for ANY reason, period. But let's forget that for a moment. You nil the FMyVar member when freeing the TMyClass object, with the expectation that you can still access FMyVar later (which you can't). If the memory that FMyVar was occupying gets reused and overwritten before the callback is invoked, that memory might not be zeroed out anymore from the earlier nil. And if it is not, then Assigned(FMyVar) will return True instead of False (if it doesn't just crash outright), and then you will try to call FMyVar.Add(...) and crash... or worse corrupt random memory trying to write to memory that it doesn't own. 1 Share this post Link to post
Rollo62 551 Posted February 25 Ok, you both are right, but I still wonder why its used in so many places, if its that unnecessary. The "reduce" was intended as fast fix, if you have no other choice to complete rework or repair anything in time, but you have to ship an update fast, used more or less like as a debugging tool. There must be at least one real use-case, where FAN makes perfectly sense. 12 hours ago, Brandon Staggs said: For example, I do this if I have a lazy-loaded class field exposed as a property that is initialized in is getter. If there is something that invalidates the reference, it needs to be nilled so that it will not be freed again when the class is freed (double-freed), and so that it can be re-initialized the next time the property is read. Yes, I already mentioned this use-case, so is this the only one? Why are there so many places using FAN during Create/Destroy, without any lazy injection? I only can think of critical timing or race-condition protection somehow. Share this post Link to post
Dalija Prasnikar 1442 Posted February 25 14 minutes ago, Rollo62 said: Ok, you both are right, but I still wonder why its used in so many places, if its that unnecessary. Because it is a plague 14 minutes ago, Rollo62 said: Yes, I already mentioned this use-case, so is this the only one? 15 minutes ago, Rollo62 said: Yes, I already mentioned this use-case, so is this the only one? Why are there so many places using FAN during Create/Destroy, without any lazy injection? Reusing is the one scenario. Another scenario which you can see in very complex destructors which are part of some deep class hierarchy. It is not to prevent concurrency issues (because it can't prevent those), but it is used to prevent accessing already released fields during more complex cleanup. In such cases it must be paired with is Assigned checks. But this is rarely needed outside frameworks like VCL and FMX (and even there it is used in many places where it is not needed at all). Share this post Link to post
Rollo62 551 Posted February 25 44 minutes ago, Dalija Prasnikar said: Reusing is the one scenario. Another scenario which you can see in very complex destructors which are part of some deep class hierarchy. It is not to prevent concurrency issues (because it can't prevent those), but it is used to prevent accessing already released fields during more complex cleanup. In such cases it must be paired with is Assigned checks. But this is rarely needed outside frameworks like VCL and FMX (and even there it is used in many places where it is not needed at all). Thanks, that sounds like I would never consider this in the first place. This is why I am asking for a simple, generic example to better understand why this would probably make sense. Do you know a specific place in the VCL/FMX code, where it is used like that? Share this post Link to post
David Heffernan 2384 Posted February 25 I get all the arguments that using FAN in a destructor is pointless, because how can you using that reference beyond the destructor. And I understand the argument for using it in a reference for an object that exists optionally, and can be destroyed outside of the destructor. What I don't get is what the downsides of using FAN are. What are the drawbacks? Share this post Link to post
Dalija Prasnikar 1442 Posted February 25 3 hours ago, Rollo62 said: Do you know a specific place in the VCL/FMX code, where it is used like that? No. I remember seeing such code, but I cannot tell you the exact place. It is hard to find them because in most places RTL, VCL, and FMX use FreeAndNil when it is not needed at all or for lazy initialized/reusable variables. Share this post Link to post
Dalija Prasnikar 1442 Posted February 25 Just now, David Heffernan said: What I don't get is what the downsides of using FAN are. What are the drawbacks? For me it is about code intent. FreeAndNil implies reusable variables and more complex instance lifetime. Free implies the opposite. 1 1 Share this post Link to post
Anders Melander 1912 Posted February 25 4 minutes ago, Dalija Prasnikar said: For me it is about code intent. FreeAndNil implies reusable variables and more complex instance lifetime. Free implies the opposite. Instead of FreeAndNil implying a certain pattern I think it would be better to explicitly state, in a comment, when and why a certain behavior is expected. The projects I'm working on right now has something in the neighborhood of 200 calls to FreeAndNil in it. All except two are there to catch stale pointers; FreeAndNil gives us a nice AV that we can easily debug. Free would most likely give us a sporadic random error somewhere else. The two remaining cases are in a framework where we need a container var to be nilled before the object is destroyed. I won't go into why it's necessary; I'm sure you know the pattern. Anyway, for these two cases, the comments in the code clearly document why the FreeAndNil pattern is necessary. This is an old project and the introduction of FreeAndNil, where it makes sense of course, has helped us catch and eliminate countless bugs. Before I took over as the lead the code was littered with hundreds of empty try..except blocks simply because they had given up on trying to find the cause of the exceptions. 2 Share this post Link to post
Dalija Prasnikar 1442 Posted February 25 42 minutes ago, Anders Melander said: Instead of FreeAndNil implying a certain pattern I think it would be better to explicitly state, in a comment, when and why a certain behavior is expected. Of course, but plenty of code doesn't have that. Share this post Link to post
Rollo62 551 Posted February 25 @Anders Melander I found an older case of yours, here at DevExpress. https://supportcenter.devexpress.com/ticket/details/t812550/an-av-occurs-if-the-spell-checker-whose-usethreadedload-property-is-set-to-true-reloads Which speaks against FreeAndNil too. Share this post Link to post
Anders Melander 1912 Posted February 25 4 hours ago, Rollo62 said: @Anders Melander I found an older case of yours, here at DevExpress. Real life race condition :-) 1 Share this post Link to post
Brandon Staggs 340 Posted Wednesday at 05:15 PM (edited) On 2/25/2025 at 7:18 AM, David Heffernan said: What I don't get is what the downsides of using FAN are. What are the drawbacks? Code obfuscation: why is it being used? What is the intent? Why did the author of this code deem it necessary to assign free to a variable that appears to be going out of scope? What, as the maintainer, am I not understanding? Other than that, nothing. It's just a small waste of cpu cycles. EDIT: Actually, nilling an object reference with FAN can hide other logic errors such as some code path that could lead to free unintentionally being called a second time. Since free checks for a nil Self, it succeeds, even if it should lead to an AV due to an erroneous double-free. Depending on how that second call to free is reached you could be making it harder for the logic error to surface as an AV. Edited Wednesday at 05:24 PM by Brandon Staggs 1 Share this post Link to post
Brandon Staggs 340 Posted Wednesday at 05:17 PM (edited) On 2/25/2025 at 1:40 AM, Rollo62 said: I only can think of critical timing or race-condition protection somehow. How can FreeAndNil help with race conditions? There is no locking around what FreeAndNil does, and if it is being used in a threading scenario without proper locking, you are asking for race conditions by using it. Edited Wednesday at 05:37 PM by Brandon Staggs Share this post Link to post
Brandon Staggs 340 Posted Wednesday at 05:22 PM (edited) On 2/25/2025 at 7:59 AM, Anders Melander said: FreeAndNil gives us a nice AV that we can easily debug. This idea has already been debunked in this thread. For example, you can call any function you want on a nil object pointer and those functions could easily affect other things in memory (global variables, for example). It will only AV if that function somehow leads to instance memory being used. For example, you can easily call .Free on a nil object pointer, and it will succeed just fine, and you may actually be hiding a logic error in your code by nilling the object before calling free a second time. Edited Wednesday at 05:27 PM by Brandon Staggs Share this post Link to post
Stefan Glienke 2058 Posted Wednesday at 05:34 PM Using FreeAndNil is the very essence of https://en.wikipedia.org/wiki/Cargo_cult_programming 2 Share this post Link to post
Anders Melander 1912 Posted Wednesday at 09:18 PM 3 hours ago, Brandon Staggs said: This idea has already been debunked in this thread. Oh really? It appears to me that you are arguing a theoretical standpoint against the actual real world experience I have with finding stale object pointers using FreeAndNil. 3 hours ago, Brandon Staggs said: It will only AV if that function somehow leads to instance memory being used. Yes, that's the point. Did anyone claim otherwise? 3 hours ago, Brandon Staggs said: For example, you can easily call .Free on a nil object pointer, and it will succeed just fine It will succeed because it has been designed to do so. How is that relevant to FreeAndNil? 3 hours ago, Brandon Staggs said: you may actually be hiding a logic error in your code by nilling the object before calling free a second time. What second time? What logic error? What are you even talking about? All this focus on free is pretty irrelevant to my use of FreeAndNil. I'm obviously not using it to guard against double frees because it doesn't do that. I'm using it to catch access though stale object pointers. End of story. I like to think that I actually know pretty well what I'm doing but I get the impression that you imagine I code by just throwing stuff against the wall to see what sticks. Share this post Link to post
Anders Melander 1912 Posted Wednesday at 09:25 PM 3 hours ago, Stefan Glienke said: Using FreeAndNil is the very essence of https://en.wikipedia.org/wiki/Cargo_cult_programming That's a pretty unnuanced statement. One could just as easily, and just as unnuanced, argue that not using it is CCP. If you use something, with a specific purpose, how is that CCP? Share this post Link to post
Brandon Staggs 340 Posted Wednesday at 09:36 PM 3 minutes ago, Anders Melander said: I'm using it to catch access though stale object pointers. End of story. To be precise, you are using it to catch access to NILLED object pointers. And you believe this is a debugging tool. But really this is just debugging theater. 4 minutes ago, Anders Melander said: Yes, that's the point. Did anyone claim otherwise? Anyone using FreeAndNil to force AVs when the object reference is next used is de-facto claiming otherwise, and this is where you seem to have gotten lost in my explanation. A *LOT* can happen on a nilled object reference without creating an AV. 7 minutes ago, Anders Melander said: It will succeed because it has been designed to do so. How is that relevant to FreeAndNil? Understanding why it is designed that way should be enough to answer your own questions about why you should not be abusing FreeAndNil as a debugging tool. There are purpose-built tools for catching use-after-free conditions. FreeAndNil is not one of them. I am just saying it is better to use the purpose-built tools for this instead of relying on a side-affect of FreeAndNil which can only catch use-after-free SOMETIMES. In the projects I work on where FreeAndNil is used everywhere (without need) I just assume that I cannot know for sure if those variables are actually intended to be used again or not. That's fine. In my own code I just make my intent clear by only using FreeAndNil when it is appropriate for the code -- not as a halfway debugging tool. 1 Share this post Link to post
Anders Melander 1912 Posted Wednesday at 10:14 PM 11 minutes ago, Brandon Staggs said: A *LOT* can happen on a nilled object reference without creating an AV. I have not claimed otherwise. It's not a magic "find all your bugs" tool. It's a "better than nothing" tool. Again, you are arguing against real world experience on actual code. I don't see the point. 14 minutes ago, Brandon Staggs said: Understanding why it is designed that way should be enough to answer your own questions about why you should not be abusing FreeAndNil as a debugging tool. I understand it and no, (roses are red, violets are blue) it does not answer my question and neither did you. 16 minutes ago, Brandon Staggs said: There are purpose-built tools for catching use-after-free conditions. Such as? Debug memory managers are not suited for this use case; They can not be used in production code because of their overhead. FreeAndNil has practically no overhead. 20 minutes ago, Brandon Staggs said: a side-affect of FreeAndNil which can only catch use-after-free SOMETIMES. Again, I never claimed otherwise. Sometimes is better better than never. If there was a better alternative I would happily use that but I'm not hearing any. 22 minutes ago, Brandon Staggs said: In my own code I just make my intent clear by only using FreeAndNil when it is appropriate for the code That's fine. In our code we make our intent clear by documenting it: With comments in the code where we rely on the order of nil and free. With a section in our development guidelines and style guide about all the other cases; When, why, and how and when not to use it. Share this post Link to post
Brandon Staggs 340 Posted Wednesday at 10:42 PM 19 minutes ago, Anders Melander said: I understand it and no, (roses are red, violets are blue) it does not answer my question and neither did you. Assuming this is what you want me to explain: 5 hours ago, Brandon Staggs said: you can easily call .Free on a nil object pointer, and it will succeed just fine, and you may actually be hiding a logic error in your code by nilling the object before calling free a second time. If you have two places that call FreeAndNil on the same reference, and a logic problem that can lead to both places being called without a clear intent to do so, you will not know about the second FreeAndNil because it will succeed and move on, where a second call to .Free will instead cause a pointer error. Is the second call to FreeAndNil a problem? Maybe not, but the code that runs around it is working on the assumption that the pointer is valid, and you have hidden an error that would expose the problem. 23 minutes ago, Anders Melander said: Again, you are arguing against real world experience on actual code. I don't see the point. David asked what the harm in using FreeAndNil can be. That's what we are discussing. You're allowed to disagree, of course. But the point is to answer the questions about why FreeAndNil should be used for its intended purpose, rather than a debugging tool. Share this post Link to post
Anders Melander 1912 Posted Wednesday at 11:07 PM Just now, Brandon Staggs said: you will not know about the second FreeAndNil because it will succeed and move on, where a second call to .Free will instead cause a pointer error. Okay, now I understand what you meant. Yes, it's true that I'm trading the ability to catch one problem for another. However, the problem you are describing does not seem to be one that we are experiencing much if ever, so I'll take that trade. Regardless, we have made an active choice to use FreeAndNil this way. Not because we don't know any better but because we have a specific (recurring, I might add) problem that it helps us solve. I totally get the argument against just mindlessly using it CCP style but I can't really see how that applies to how we use it. I'd still like to know about these alternatives I should be using though... 11 minutes ago, Brandon Staggs said: David asked what the harm in using FreeAndNil can be. That's what we are discussing. You're allowed to disagree, of course. But the point is to answer the questions about why FreeAndNil should be used for its intended purpose, rather than a debugging tool. Well, that's nice but no that's not what we are discussing. I gave an example of how and why we used it and you said that that usage had been "debunked". Share this post Link to post
Stefan Glienke 2058 Posted Wednesday at 11:46 PM (edited) 2 hours ago, Anders Melander said: If you use something, with a specific purpose, how is that CCP? Because as you can read in this thread people advocate for using it everywhere instead of at those rare places it's designed for: making sure the reference is set to nil before the instance is destroyed because any code being called during destruction might reach back to this very reference. (which is the reason its name is not even correct - it should have been named NilAndFree) Edited Wednesday at 11:47 PM by Stefan Glienke 1 Share this post Link to post
Darian Miller 369 Posted Thursday at 02:55 AM (edited) One step further... I worked with a Delphi developer who rarely used Free, and tried to only use Destroy. Everyone seems to have an opinion on Free vs FreeAndNil but he was the only one that ever went further and said Destroy vs Free. Some of the same arguments could be had for using Destroy vs Free. (But I still use .Free) Edited Thursday at 02:55 AM by Darian Miller Share this post Link to post