Valgrind debug info (-gv) with whole program optimization (-OwALL) confused by generics involving records
Summary
An EAbstractError gets thrown when you call the constructor of an empty generic class whose type argument is a record in another unit after doing whole-program optimization with -gv.
System Information
- Operating system: Ubuntu Linux
- Processor architecture: x86-64
- Compiler version: trunk as of 2025-07-04
- Device: Computer
Steps to reproduce
This is testunit.pas:
{$MODE OBJFPC}
{$MODESWITCH ADVANCEDRECORDS+}
unit testunit;
interface
type
EmptyRecord = record end;
implementation
end.
This is test.pas:
{$MODE OBJFPC}
program test;
uses
sysutils, testunit;
type
generic TGeneric <T> = class end;
type
TA = specialize TGeneric<EmptyRecord>;
var
A: TA;
begin
A := TA.Create();
A.Free();
end.
This program should do nothing visible. It correctly does this in most modes.
If you run the following commands, however:
fpc test.pas -XX -B -O4 -OWALL -FWtest.opt
fpc test.pas -gv -XX -B -O4 -OwALL -Fwtest.opt
./test
...you get the following output:
An unhandled exception occurred at $000000000041D98C:
EAbstractError: Abstract method called
$000000000041D98C
$000000000040122A
After some poking around, I was able to determine that it happens at the end of the constructor. My guess is that the compiler implicitly calls AfterConstruction(), but the symbol liveness code doesn't notice. The VMT has that entry (and most others) removed in the version after using -gv:
VMT_$P$TEST_$$_TGENERIC$1$CRC9108733E_CRCEEEA93B8:
.quad 16,-16
.quad VMT_$SYSTEM_$$_TOBJECT$indirect
.quad .Ld1
.quad 0,0,0
.quad RTTI_$P$TEST_$$_TGENERIC$1$CRC9108733E_CRCEEEA93B8
.quad 0,0,0,0
.quad FPC_ABSTRACTERROR # Destroy
.quad SYSTEM$_$TOBJECT_$__$$_NEWINSTANCE$$TOBJECT
.quad FPC_ABSTRACTERROR # FreeInstance
.quad FPC_ABSTRACTERROR # SafeCallException
.quad FPC_ABSTRACTERROR # DefaultHandler
.quad FPC_ABSTRACTERROR # AfterConstruction
.quad FPC_ABSTRACTERROR # BeforeDestruction
.quad FPC_ABSTRACTERROR # DefaultHandlerStr
.quad FPC_ABSTRACTERROR # Dispatch
.quad FPC_ABSTRACTERROR # DispatchStr
.quad FPC_ABSTRACTERROR # Equals
.quad FPC_ABSTRACTERROR # GetHashCode
.quad FPC_ABSTRACTERROR # ToString
.quad 0
The version without -gv has all of them:
VMT_$P$TEST_$$_TGENERIC$1$CRC08EA153F_CRCEEEA93B8:
.quad 16,-16
.quad VMT_$SYSTEM_$$_TOBJECT$indirect
.quad .Ld1
.quad 0,0,0
.quad RTTI_$P$TEST_$$_TGENERIC$1$CRC08EA153F_CRCEEEA93B8
.quad 0,0,0,0
.quad SYSTEM$_$TOBJECT_$__$$_DESTROY
.quad SYSTEM$_$TOBJECT_$__$$_NEWINSTANCE$$TOBJECT
.quad SYSTEM$_$TOBJECT_$__$$_FREEINSTANCE
.quad SYSTEM$_$TOBJECT_$__$$_SAFECALLEXCEPTION$TOBJECT$POINTER$$HRESULT
.quad SYSTEM$_$TOBJECT_$__$$_DEFAULTHANDLER$formal
.quad SYSTEM$_$TOBJECT_$__$$_AFTERCONSTRUCTION
.quad SYSTEM$_$TOBJECT_$__$$_BEFOREDESTRUCTION
.quad SYSTEM$_$TOBJECT_$__$$_DEFAULTHANDLERSTR$formal
.quad SYSTEM$_$TOBJECT_$__$$_DISPATCH$formal
.quad SYSTEM$_$TOBJECT_$__$$_DISPATCHSTR$formal
.quad SYSTEM$_$TOBJECT_$__$$_EQUALS$TOBJECT$$BOOLEAN
.quad SYSTEM$_$TOBJECT_$__$$_GETHASHCODE$$INT64
.quad SYSTEM$_$TOBJECT_$__$$_TOSTRING$$ANSISTRING
.quad 0