Skip to content

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
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information