[fpc-pascal] FPC 3.3.x breaks the Firebird Project's Firebird.pas

Tony Whyman tony.whyman at mccallumwhyman.com
Thu May 2 13:02:26 CEST 2024


This is a problem reported to me by an IBX user. I have not yet 
confirmed it (need to find the time to set up the latest development 
branch of FPC), but the issue looks solid, and is due to the following 
addition to TObject (copied from the GitLab master branch)

|TObject = class|{$IFDEF SYSTEM_HAS_FEATURE_MONITOR}
strictprivate
_MonitorData : Pointer;
private
functionSetMonitorData(aData,aCheckOld : Pointer):Pointer; inline;
functionGetMonitorData:Pointer; inline;
{$ENDIF}
        ...

Since Firebird 3.0, the Firebird project has provided a file called 
"Firebird.pas" in order to provide an interface to Pascal (both Delphi 
and FPC) from a C++ environment. There is an underlying assumption in 
the interface. That is TObject contains no fields.

The idea is simple enough. There is a single entry point to the Firebird 
client library with the Pascal signature

function fb_get_master_interface : IMaster; cdecl;

This returns a pointer to a structure that may contain fields but is 
primarily a list of pointers to cdecl functions. These functions can 
perform various tasks. In the case of IMaster, they can also return 
similar structures representing other "interfaces".

On the Pascal side, IMaster is defined as a class with no virtual 
methods and a single field called "vTable" and this is set to the 
pointer to the structure returned by fb_get_master_interface. The rest 
of the class comprises methods used to call functions from the vTable. 
This makes IMaster look like a normal class and hides the use of 
function pointers. The code is generated by a program know as "cloop". 
All Firebird interfaces declared in Firebird.pas follow the same approach.

Given the assumption that TObject defines no fields, it is possible to 
coerce the pointer returned by fb_get_master_interface to appear as an 
object "instance" of the IMaster class, and similarly for every other 
Firebird interface class. This coercion ceases to be valid as soon as a 
field, such as _MonitorData is added to TObject.

It is probably a valid argument to say that this is Firebird's problem 
as the TObject definition is an internal data structure. However, this 
ignores a serious real world problem. A fix or workaround is needed and 
that has to be in Firebird.pas. It would be a logistic nightmare to try 
and change the C++ Firebird client DLL/SO.

Also, does anyone know whether a similar problem will arise with Delphi, 
or is thus just an FPC issue?

One of the following seems to be needed:

a) Rewriting Firebird.pas to set the vTable field explicitly rather than 
implicitly through coercion - ideally without breaking any user code... 
(note: no current need to free IMaster etc)

b) Taking a different approach to introducing _MonitorData e.g.

i) Putting in a class helper (is this possible?)

ii) Having a version of TObject (e.g. TUnmonitoredObject) which is the 
current TObject and making TObject a descendent class introducing 
_MonitorData. The Firebird classes can then descend from 
TUnMonitoredObject, either explicitly or as a result of a new compiler 
directive setting the default class ancestor.

iii) Anything else that works.

I am primarily looking for a solution that will work with IBX, but also 
one that I can suggest to the Firebird Devs to make generally available.

Tony Whyman

MWA Software
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-pascal/attachments/20240502/21865394/attachment.htm>


More information about the fpc-pascal mailing list