I was talking to a co-worker the other day about how you can leak a string in Delphi if you really mess things up. By default strings are reference counted and automatically allocated, so they typically just work without any thought - no need for manual allocation, size calculations, or memory management.
But I remember reading once that there is a way to leak a string directly (without including it in an object that gets leaked). It seems like it had something to do with passing a string by reference and then accessing it from a larger scope from within the routine it was passed to. Yeah, I know that is vague, which is why I am asking the question here.
I don't know about the issue in your second paragraph, but I was bitten once by leaked strings in a record.
If you call FillChar() on a record that contains strings you overwrite the ref count and the address of the dynamically allocated memory with zeroes. Unless the string is empty this will leak the memory. The way around this is to call Finalize() on the record before clearing the memory it occupies.
Unfortunately calling Finalize() when there are no record members that need finalizing causes a compiler hint. It happened to me that I commented out the Finalize() call to silence the hint, but later when I added a string member to the record I missed uncommenting the call, so a leak was introduced. Luckily I'm generally using the FastMM memory manager in the most verbose and paranoid setting in debug mode, so the leak didn't go unnoticed.
The compiler hint is probably not such a good thing, silently omitting the Finalize() call if it's not needed would be much better IMHO.
No, I don't think such a thing can happen. It's possible for a string variable to obtain a value that you didn't expect, but it won't leak memory. Consider this:
Here
One
's argument is declared const, so supposedly, it won't change. But thenOne
circumvents that by changing the actual parameter instead of the formal parameter. ProcedureTwo
"knows" thatOne
's argument is const, so it expects the actual parameter to retain its original value. The assertion fails.The string hasn't leaked, but this code does demonstrate how you can get a dangling reference for a string.
Arg
is a local alias ofGlobal
. Although we've changedGlobal
,Arg
's value remains untouched, and because it was declared const, the string's reference count was not incremented upon entry to the function. ReassigningGlobal
dropped the reference count to zero, and the string was destroyed. DeclaringArg
as var would have the same problem; passing it by value would fix this problem. (The call toUniqueString
is just to ensure the string is reference-counted. Otherwise, it may be a non-reference-counted string literal.) All compiler-managed types are susceptible to this problem; simple types are immune.The only way to leak a string is to treat it as something other than a string, or to use non-type-aware memory-management functions. Mghie's answer describes how to treat a string as something other than a string by using
FillChar
to clobber a string variable. Non-type-aware memory functions includeGetMem
andFreeMem
. For example:There are two ways to fix it. One is to call
Initialize
andFinalize
:The other is to use type-aware functions:
Another way to leak a string is to declare it as a threadvar variable. See my question for details. And for the solution, see the solution on how to tidy it.
I think this might have been similar to what I was thinking of. It is the reverse of a string leak, a string that gets collected early:
Actually, passing string as CONST or non const are the same in term of reference count in Delphi 2007 and 2009. There was a case that causing access violation when string is passed as CONST. Here is the problem one