← board

Dynamic array as a record field is corrupted (value return + var-param assign)

Summary

A record containing a dynamic-array field is mishandled by codegen:

lib/rtl/zlib.pas:27 already documents the limitation ("The pinned stable compiler has trouble with dynamic arrays stored in records and with passing dynamic arrays through several parameter layers") and works around it with module globals — but there was no ticket. This files it.

Minimal repro (FPC-verified correct)

program Rec;
type TR = record n: Integer; a: array of Integer; end;
procedure Fill(var r: TR);
var loc: array of Integer; i: Integer;
begin
  SetLength(loc, 3);
  for i := 0 to 2 do loc[i] := (i+1)*10;
  r.n := 3;
  r.a := loc;            { assign local dynarray into record field (var param) }
end;
function SumR(const r: TR): Integer;
var i, s: Integer;
begin
  s := 0;
  for i := 0 to r.n - 1 do s := s + r.a[i];
  Result := s;
end;
var x: TR;
begin
  Fill(x);
  writeln('len=', Length(x.a), ' a0=', x.a[0], ' a2=', x.a[2], ' sum=', SumR(x), ' want 60');
end.
compiler result
FPC (fpc -Mobjfpc) len=3 a0=10 a2=30 sum=60 want 60
PXX v33 (pinned) SIGSEGV (len= then crash)

A second symptom (record returned by value) shows up via function ParseDIMACS(const s): TCNF returning a record with two dynarray fields: the caller reads Length(cnf.Lits) = 2071656378828587104 (garbage).

Likely area

Managed-field handling for records whose fields are dynamic arrays: the array field's reference/refcount is not initialised/copied on record assignment, var-param store, or by-value return. Compare with the already-fixed managed-string record work (feature-cross-managed-aggregates) — dynamic-array fields appear to have been missed.

Workaround in use

lib/rtl/sat.pas (like zlib) keeps the formula + working arrays as module globals instead of a TCNF record. Once this is fixed, a clean record-based API becomes possible.

Log