management operators double free after nested function

Summary

finalize is called twice if the record is used in a nested function

System Information

  • Operating system: Ubuntu 22.04
  • Processor architecture: x86-64
  • Compiler version: 3.3.1 36a2835f LLVM

Example Project

program Project1;
{$mode objfpc}{$ModeSwitch arrayoperators}{$ModeSwitch advancedrecords}

uses sysutils;
type IXQValue = record //something like a smart pointer
  x: pinteger;
  class operator initialize(var xx: IXQValue);
  class operator finalize(var xx: IXQValue);
  class operator addref(var xx: IXQValue);
  class operator Copy(constref s: IXQValue; var xx: IXQValue);
  class function create: IXQValue;static;
end;
class operator IXQValue.initialize(var xx: IXQValue);
begin
  xx.x := new(pinteger);
  xx.x^ := 1;
end;

class operator IXQValue.finalize(var xx: IXQValue);
begin
  dec(xx.x^);
  writeln(inttohex(ptruint(@xx),8), ' ',inttohex(ptruint(xx.x),8), ' ', xx.x^);
 // if xx.x^ = 0 then dispose(xx.x);
end;

class operator IXQValue.addref(var xx: IXQValue);
begin
  inc(xx.x^);
end;

class operator IXQValue.Copy(constref s: IXQValue; var xx: IXQValue);
begin
  inc(s.x^);
  write('  copy ');
  //finalize(xx);
//  writeln(inttohex(ptruint(@xx),8), ' ',inttohex(ptruint(xx.x),8));
  dec(xx.x^);
  writeln(inttohex(ptruint(@xx),8), ' ',inttohex(ptruint(xx.x),8), ' ', xx.x^);
  xx.x := s.x;
end;

class function IXQValue.create: IXQValue;
begin
  //result := default(IXQValue);
end;



function test(const previous: IXQValue): IXQValue;


var
  newList: IXQValue;
  {$define doublefree}
  {$ifdef doublefree}
procedure print(const v: IXQValue);
var
  temp: IXQValue;

begin
 writeln(newList.x^);

end;

{$endif}
var
  i: SizeInt;
  resultList: IXQValue;

  tempList: IXQValue;




begin
    resultList:=ixqvalue.create;
    newList := ixqvalue.create;
  newlist := ixqvalue.create;

     tempList := newList;
     resultList := tempList        ;


  writeln(result.x^);
 writeln('newList: ',inttohex(ptruint(@newList), 8));
  writeln('tempList: ',inttohex(ptruint(@tempList), 8));
  result := resultList;
end;
begin
  test(ixqvalue.create);
end.

What is the current bug behavior?

  copy 7FFC27A36C78 7F4ACA41B140 0
  copy 7FFC27A36C78 7F4ACA41B1C0 1
  copy 7FFC27A36C80 7F4ACA41B180 0
  copy 7FFC27A36C98 7F4ACA41B160 0
1
newList: 7FFC27A36C78
tempList: 7FFC27A36C80
  copy 7FFC27A36CD8 7F4ACA41B100 0
7FFC27A36CA0 7F4ACA41B1A0 4
7FFC27A36CA8 7F4ACA41B1C0 0
7FFC27A36C78 7F4ACA41B1A0 3
7FFC27A36C78 7F4ACA41B1A0 2
7FFC27A36C98 7F4ACA41B1A0 1
7FFC27A36C80 7F4ACA41B1A0 0
7FFC27A36CD8 7F4ACA41B1A0 -1
7FFC27A36CE0 7F4ACA41B0E0 0
7FFC27A36CD8 7F4ACA41B1A0 -2

Finalize is called twice on 7FFC27A36C78

What is the expected (correct) behavior?

only call finalize once

The counter should not become -2

(not sure if -1 is correct at the end)

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information