There is a bug in Generics.Defaults unit in Delphi 2009. If you read my previous post: Generic Defaults you should know already about the “3 bytes long” data types and how are those passed as const parameters to a function. I know I had problems with that (had to create a special case for those) so how did CodeGear developers get around that? Simply – they didn’t.
Consider this piece of code:
type
TMyStruct = packed record
a1, a2, a3 : Byte;
end;
procedure TestDefaults()
var
comp : IComparer<TMyStruct>;
s1, s2 : TMyStruct;
I : Integer;
begin
comp := TComparer<TMyStruct>.Default;
FillChar(s1, 3, 0);
FillChar(s2, 3, 1);
for I := 0 to 10000 do
comp.Compare(s1, s2);
end;
After a few loops you will get a pretty ugly “Access Violation” because the stack is corrupted. This happens because the TComparer
function Equals_Binary(Inst: PSimpleInstance;
const Left, Right): Boolean;
function Compare_Binary(Inst: PSimpleInstance;
const Left, Right): Integer;
function GetHashCode_Binary(Inst: PSimpleInstance;
const Value): Integer;
Surely they expect Left and Right parameters to be passed as addresses in EDX/ECX registers. The problem is obvious: 3 byte data structures are passes in the stack! The called function is expected to cleanup the stack afterward using a “ret 8” instruction. This means that the stack keeps building up 2 integers on each call until it happens to address invalid memory (this is why I used a loop there).
I know it’s a very “exotic” case where you actually have to use a packed data-type (defaults are aligned to 4 bytes so there is no problem) but it’s still a bug.
More to come.