test(codegen-native): lock in offset-0 sret-Result field read
Adds an e2e regression (both backends) that read-modifies Result.A (offset 0) of a managed sret-returned record mid-body. The native offset-0 field-read shortcut used to load the Result slot directly — but for an sret function that slot holds a POINTER to the caller's buffer, so the pointer was read as the field value (garbage). The fix already landed (the inline-asm commit routes the offset-0 integer field-read leaf through EmitLocalRecordBase so the sret-Result deref happens); this test, from Andrew Haines's parallel fix (236e9525), locks it in. His code change is omitted as a duplicate of the already-landed fix. Co-authored-by: Andrew Haines <andrewd207@aol.com>
This commit is contained in:
parent
801feb0792
commit
bcb2f68222
|
|
@ -133,6 +133,15 @@ type
|
|||
statement form (inherited M;). }
|
||||
procedure TestRun_InheritedRecordReturn_ManagedField;
|
||||
procedure TestRun_InheritedRecordReturn_StatementForm;
|
||||
{ Regression: reading the OFFSET-0 field of an sret function's own Result
|
||||
mid-body (read-modify) after assigning Result from a record-returning
|
||||
call. The native offset-0 field-read shortcut loaded the Result slot
|
||||
directly — but for an sret function that slot holds a POINTER to the
|
||||
record, so the buffer pointer was read as the field value (garbage).
|
||||
Offset>0 fields were fine (they always deref). Both backends. (The fix
|
||||
lives in the inline-asm commit; this test, from Andrew's parallel fix,
|
||||
locks it in.) }
|
||||
procedure TestRun_SretResult_ReadModifyOffsetZeroField;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
|
@ -1066,6 +1075,35 @@ begin
|
|||
AssertRunsOnAll(Src, '105' + LE + 'base' + LE, 0);
|
||||
end;
|
||||
|
||||
procedure TE2ERecordReturnTests.TestRun_SretResult_ReadModifyOffsetZeroField;
|
||||
const
|
||||
Src = '''
|
||||
program P;
|
||||
type TR = record A: Integer; S: string; B: Integer; end;
|
||||
function Raw(N: Integer): TR;
|
||||
begin
|
||||
Result.A := N;
|
||||
Result.S := 'hi';
|
||||
Result.B := 20
|
||||
end;
|
||||
function Make(N: Integer): TR;
|
||||
begin
|
||||
Result := Raw(N);
|
||||
Result.A := Result.A + 1
|
||||
end;
|
||||
var R: TR;
|
||||
begin
|
||||
R := Make(10);
|
||||
WriteLn(R.A, ' ', R.S, ' ', R.B)
|
||||
end.
|
||||
''';
|
||||
begin
|
||||
if not ToolchainAvailable() then begin Ignore('toolchain unavailable'); Exit; end;
|
||||
{ The string field forces a genuine sret return (24 bytes); reading
|
||||
Result.A (offset 0) mid-body must deref the Result pointer. }
|
||||
AssertRunsOnAll(Src, '11 hi 20' + LE, 0);
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterTest(TE2ERecordReturnTests);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue