You just blew the stack variables there. Both the B
pointer (in its entirety) and partially the pointer S
( (Length(b) - SizeOf(b))
bytes of it ).
What is b
? it is a some complex structure, a handle, a pointer. Usually You do not want to destroy memory structure, you want to put the data into the cells. But in your example you just wiped out the whole memory structures allocated on stack. Including, probably, the string itself.
The following program works as expected in Delphi XE2 - see what is there instead of Zero Memory. Read what are dynamic arrays in Delphi and how they are allocated from CPU Assembler point of view when you want to use low-level tricks as raw pointers ( or untyped variables like in ZeroMemory
)
program Project11;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
procedure fill(var b: TBytes);
begin
SetLength(b,5);
// b[0]:=61; b[1]:=61; b[2]:=61; b[3]:=61; b[4]:=61;
FillChar(b[Low(b)], Length(b), 61); // Less copy-paste, more program structure
// Notice, above i take pointer to the cell inside the array,
// not to the array the container itself.
// That is both safer and does document the intention of the code
end;
Procedure SOTest();
var
s: ansistring ;
b: TBytes;
begin
fill(b);
s := StringOf( b );
// ZeroMemory(@b, Length(b)); -- destroying the pointer instead of freeing memory - is a memory leak
// FillChar(b, Length(b), 0); -- same as above, written in Pascal style, rather than C style.
b := nil; // this really does free the DYNAMIC ARRAYS. Laconic but prone to errors if mistyped.
// SetLength(b, 0); -- more conventional and safe method to do the same: free string or dyn-array.
// Anyway that is unnecessary - both b and s would anyway be auto-freed before the function exit.
Writeln(Length(s):4, ' ', s);
end;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
SOTest;
Write('Press Enter to exit;'); ReadLn;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
See manuals.
- http://docwiki.embarcadero.com/Libraries/XE4/en/System.FillChar
- http://docwiki.embarcadero.com/RADStudio/XE4/en/Parameters_(Delphi)#Untyped_Parameters
- http://docwiki.embarcadero.com/RADStudio/XE4/en/Structured_Types#Dynamic_Arrays
- http://docwiki.embarcadero.com/Libraries/XE4/en/System.SysUtils.TBytes
- http://docwiki.embarcadero.com/Libraries/XE4/en/System.SysUtils.StringOf
So the next question is WHY were you trying to call ZeroMemory, what is the point there ? IS there soem attempt to destroy a cypher key or other sensitive data ? http://www.catb.org/~esr/faqs/smart-questions.html#goal
If you only want to assure that "s" variable does not have any external references - there is a special function for it, UniqueString
.
However in this particular workflow and this particular Delphi version that could not happen anyway. Read again manual for StringOf
- it returns a UnicodeString
temporary hidden variable. That variable is encoded in UTF-16
in XE4, which means having 2 bytes per letter, which means the original byte-chain would not suit anyway and would be transformed into new buffer.
After that you convert the UnicodeString
temporary hidden variable into AnsiString
variable s
having one byte per letter, so it also can not have references to the temp-var, but would allocate yet another independent buffer to hold the transformed data.
As you can see there is two necessary copy-with-transformation operations, both of which make keeping data references just impossible.