вторник, 20 октября 2020 г.

#871. Compilation bug in Sydney under 64 bit

https://quality.embarcadero.com/browse/RSP-31389

Code with bug:
unit tcOldObject1;

interface

uses
 TestFrameWork
;

type
 TtcOldObject1 = class(TTestCase)
  published
   procedure DoIt;
 end;//TtcOldObject1

 TOldObject1 = object
  public
   rF: Pointer;
 end;//TOldObject1

 TOldObject2 = object
  public
   rF: TOldObject1;
 end;//TOldObject2

function TOldObject2_C(const anObj: TOldObject1): TOldObject2;

implementation

function TOldObject2_C(const anObj: TOldObject1): TOldObject2;
begin
 // - here lost pointer dereference
 // Compiler makes the code:
 (*
 push rbp
 sub rsp,$10
 mov rbp,rsp
 mov [rbp+$20],rcx
 mov rax,[rbp+$20]
 mov [rbp+$08],rax
 mov rax,[rbp+$08]
 lea rsp,[rbp+$10]
 pop rbp
 ret
 *)
 // But the correct one is:
 (*
 push rbp
 sub rsp,$10
 mov rbp,rsp
 mov [rbp+$20],rcx
 mov rax,[rbp+$20]
 mov rax,[rax]
 mov [rbp+$08],rax
 mov rax,[rbp+$08]
 lea rsp,[rbp+$10]
 pop rbp
 ret
 *)
 // Lost instruction:
 (*
 mov rax,[rax]
 *)
 // - dereference pointer to anObj lost !!!
 Result.rF := anObj;
end;//TOldObject2_C

procedure TtcOldObject1.DoIt;
var
 l_O1 : TOldObject1;
 l_O2 : TOldObject2;
begin
 l_O1.rF := TypeInfo(Integer);
 l_O2.rF := l_O1;
 Self.Check(l_O2.rF.rF = l_O1.rF); // Right !
 l_O2 := TOldObject2_C(l_O1);
 Self.CheckFalse(l_O2.rF.rF = l_O1.rF); // Ooops !
 Self.CheckTrue(l_O2.rF.rF = @l_O1.rF); // Ooops !
end;//TtcOldObject1.DoIt

initialization
 TestFrameWork.RegisterTest(TtcOldObject1.Suite);
end.
Code without bug:
unit tcRecord1;

interface

uses
 TestFrameWork
;

type
 TtcRecord1 = class(TTestCase)
  published
   procedure DoIt;
 end;//TtcRecord1

 TRecord1 = record
  public
   rF: Pointer;
 end;//TRecord1

 TRecord2 = record
  public
   rF: TRecord1;
 end;//TRecord2

function TRecord2_C(const anObj: TRecord1): TRecord2;

implementation

function TRecord2_C(const anObj: TRecord1): TRecord2;
begin
 Result.rF := anObj;
end;//TRecord2_C

procedure TtcRecord1.DoIt;
var
 l_O1 : TRecord1;
 l_O2 : TRecord2;
begin
 l_O1.rF := TypeInfo(Integer);
 l_O2.rF := l_O1;
 Self.Check(l_O2.rF.rF = l_O1.rF); // Right !
 l_O2 := TRecord2_C(l_O1);
 Self.CheckTrue(l_O2.rF.rF = l_O1.rF); // Right !
 Self.CheckFalse(l_O2.rF.rF = @l_O1.rF); // Right !
end;//TtcRecord1.DoIt

initialization
 TestFrameWork.RegisterTest(TtcRecord1.Suite);
end.

Комментариев нет:

Отправить комментарий