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.