The following console app works fine:
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Classes,
System.Generics.Collections;
type
TMethodList = TList<TMethod>;
const Method: TMethod = (Code:nil; Data:nil);
begin
try
var fKeyDownChain := TMethodList.Create;
try
fKeyDownChain.Add(Method);
fKeyDownChain.Remove(Method);
WriteLn(fKeyDownChain.Count);
finally
fKeyDownChain.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
ReadLn;
end.
However the exact same sequence results in an access violation when used in a larger Win64 application.
const Method: TMethod = (Code:nil; Data:nil);
begin
fKeyDownChain := TMethodList.Create;
fKeyDownChain.Add(Method);
fKeyDownChain.Remove(Method);
The error occurs when you call Remove, at the first statement of the following function of System.Generics.Defaults,
class function TComparer<T>.EQOperCompare(Self: Pointer; const Left, Right: T): Integer;
begin
if TRecEqualityOperator<T>(_GetExtInstanceData(Self, 0))(Left, Right) then
Result := 0
else
Result := BinaryCompare(@Left, @Right, SizeOf(T));
end;
In the console application this statement results in a call to TMethod.Equal, Any clues as to why the error occurs?
Update: This is a consequence of [RSP-43423] Using {$WEAKLINKRTTI ON} causes access violation on TList<T>.IndexOf method - Embarcadero Technologies. The console application also fails with {$WEAKLINKRTTI ON}.
I guess specifying a Comparer would be a workaround. Is there any other workaround apart from removing the WEAKLINKRTTI directive, which increases the size of the executable by 2Mb?
.
Beyond the executable size, this is quite a serious issue, because it makes the use of generic collections of records in components unsafe, since a user of such a component setting WEAKLINKRTTI to ON, could face unpredictable and hard to detect crashes.