On 17/10/2025 21:15, Sven Barth via fpc-devel wrote:
What is the best way to check if a virtual function in a base class has been overridden by a class that inherits the base class?

In LCL TPrinter.pas the following check is used:


procedure TPrinter.NewPage;
begin
  Inc(fPageNumber);
  if TMethod(@Self.DoNewPage).Code = Pointer(@TPrinter.DoNewPage) then
    begin
    ..
    end
 ..
end

We have run across an optimization problem with the TCocoaPrinter class and that TPrinter code.

TCocoaPrinter = class(TPrinter)

with no override of DeNewPage

David's problem is *not* due to a corruction or a bug, but due to an optimization that FPC performs that leads to different behavior, namely changing virtual methods that are empty to EmptyMethod to reduce the number of duplicate (empty) methods in the binary.

I am trying to figure out under which circumstances this would happen?
  TPrinter = class...
     procedure DoNewPage; virtual;

And the check really only makes sense for virtual methods. Well (in generics that differs, but for non virtual, both classes are known at compiletime).

So if it is a virtual method:

If the compiler optimizes @TPrinter.DoNewPage to EmptyMethod, then it would put that into the class definition?
So that is into the VMT?
And there is only one VMT?
And self is a pointer (to pointer) to that one VMT?

So then how can one be replaced, but the other not?


He says "with no override of DeNewPage". So he expects them both to be the same. I could see the opposite fail. If there was on overwritten method, and that was also empty, then the different overwritten empty method would (falsely) report as the same...
But then reporting as different?

Or does the compiler only update the VMT, but does report @TPrinter.DoNewPage to the original code? If that was the case, would/should that not be considered a bug. If the compiler replaced it, then it should report it for the original too.

If @TPrinter.DoNewPage still reports the original code (and NOT emptyproc) then that forces the original code to be included too (even though the whole optimization was to NOT include it).
Because you could then do:
  MyMeth := @TPrinter.DoNewPage;
  MyMeth();
and call the original code.

_______________________________________________
fpc-devel maillist  -  [email protected]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to