Be careful with functions that try to treat the string as a pointer, and try using FillChar or ZeroMemory to erase the contents of the string.
- This is wrong (the lines are split, you are casting someone else who is currently using the line)
- and can cause an access violation (if the line was a constant, it sits on the read-only data page in the process address space, and an attempt to write to it is an access violation)
procedure BurnString(var s: UnicodeString); begin { If the string is actually constant (reference count of -1), then any attempt to burn it will be an access violation; as the memory is sitting in a read-only data page. But Delphi provides no supported way to get the reference count of a string. It also an issue if someone else is currently using the string (ie Reference Count > 1). If the string were only referenced by the caller (with a reference count of 1), then our function here, which received the string through a var reference would also have the string with a reference count of one. Either way, we can only burn the string if there no other reference. The use of UniqueString, while counter-intuitiave, is the best approach. If you pass an unencrypted password to BurnString as a var parameter, and there were another reference, the string would still contain the password on exit. You can argue that what the point of making a *copy* of a string only to burn the copy. Two things: - if you're debugging it, the string you passed will now be burned (ie your local variable will be empty) - most of the time the RefCount will be 1. When RefCount is one, UniqueString does nothing, so we *are* burning the only string } if Length(s) > 0 then begin System.UniqueString(s);
Once you have the UnicodeString version, you can create the AnsiString and WideString :
procedure BurnString(var s: AnsiString); overload; begin if Length(s) > 0 then begin System.UniqueString(s); ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar)); //if PLongInt(PByte(S) - 8)^ = 1 then //RefCount=1 // ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar)); s := ''; end; end; procedure BurnString(var s: WideString); begin //WideStrings (ie COM BSTRs) are not reference counted, but they are modifiable if Length(s) > 0 then begin ZeroMemory(Pointer(s), System.Length(s)*SizeOf(WideChar)); //if PLongInt(PByte(S) - 8)^ = 1 then //RefCount=1 // ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar)); s := ''; end; end;
source share