← board

Field access through an interface variable is accepted and crashes (FPC rejects it)

Repro

type
  IPas0 = interface ['{11111111-0000-0000-0000-000000000001}'] function Ic0(a: longint): longint; end;
  TIfc = class(TInterfacedObject, IPas0) fi: longint; function Ic0(a: longint): longint; end;
var iw0: IPas0;
function TIfc.Ic0(a: longint): longint; begin Ic0 := a + fi; end;
begin
  iw0 := TIfc.Create;
  iw0.fi := 100;          { field access THROUGH an interface var }
  writeln(iw0.Ic0(0));
  iw0 := nil;
end.

Why

An interface value is a single pointer to the instance, but member resolution on an interface-typed expression must be restricted to the interface's method set. pxx instead resolves iw0.fi as if iw0 were the class, emitting a field load/store at the class field offset through the interface pointer — which is not a valid class-instance base in the general case (and even when it happens to alias the instance, the write corrupts adjacent state), so a later dispatch/finalize faults.

Fix

Interface-typed member access must accept only the interface's (and ancestors'/IUnknown's) methods; a field/property-backing-field name is a compile error ("interface has no member X"), matching FPC. Reject at resolution time; never lower it to a class-field access.

Acceptance

Note

Distinct from [[bug-pascal-interface-finalization-crash]] (which does NOT do field-access -through-interface — that one's trigger is still in the delta-debugged middle block). This one is minimal and FPC-oracle'd.

Log