Browse Source

LLVM: fix double init/fini of local managed variables accessed from nested functions

resolves #40392
Jonas Maebe 1 year ago
parent
commit
c96641f901
2 changed files with 66 additions and 2 deletions
  1. 2 2
      compiler/ngenutil.pas
  2. 64 0
      tests/webtbs/tw40392.pp

+ 2 - 2
compiler/ngenutil.pas

@@ -239,7 +239,7 @@ implementation
       if (target_info.system in systems_fpnestedstruct) and
          (p.nodetype=loadn) and
          (tloadnode(p).symtableentry.typ=localvarsym) and
-         (tloadnode(p).symtableentry.visibility=vis_hidden) then
+         tlocalvarsym(tloadnode(p).symtableentry).inparentfpstruct then
         begin
           p.free;
           result:=cnothingnode.create;
@@ -288,7 +288,7 @@ implementation
       if (target_info.system in systems_fpnestedstruct) and
          (p.nodetype=loadn) and
          (tloadnode(p).symtableentry.typ=localvarsym) and
-         (tloadnode(p).symtableentry.visibility=vis_hidden) then
+         tlocalvarsym(tloadnode(p).symtableentry).inparentfpstruct then
         begin
           p.free;
           result:=cnothingnode.create;

+ 64 - 0
tests/webtbs/tw40392.pp

@@ -0,0 +1,64 @@
+{$mode objfpc} {$modeswitch advancedrecords}
+
+{ define doublefree}
+var
+	InitCount: int32 = 0;
+
+type
+	ManRec = record
+		x: int32;
+		class operator Initialize(var self: ManRec);
+		class operator Finalize(var self: ManRec);
+		class operator Copy(constref b: ManRec; var self: ManRec);
+		class operator AddRef(var self: ManRec);
+	end;
+
+	class operator ManRec.Initialize(var self: ManRec);
+	begin
+		inc(InitCount);
+	end;
+
+	class operator ManRec.Finalize(var self: ManRec);
+	begin
+		dec(InitCount);
+	end;
+
+	class operator ManRec.Copy(constref b: ManRec; var self: ManRec);
+	begin
+		writeln('shouldn''t happen');
+		halt(1);
+	end;
+
+	class operator ManRec.AddRef(var self: ManRec);
+	begin
+		writeln('shouldn''t happen');
+		halt(2);
+	end;
+
+	function GetManRec: ManRec;
+	begin
+		result.x := 1;
+	end;
+
+	procedure Use(const mr: ManRec);
+	begin
+	end;
+
+	procedure Main;
+	var
+		mr: ManRec;
+	begin
+	{$ifdef doublefree}
+		GetManRec; // imperfect, double Finalize()
+	{$else}
+		mr := GetManRec; // ok
+		Use(GetManRec); // ok as well
+	{$endif}
+	end;
+
+begin
+	Main;
+	writeln('InitCount = ', InitCount, ' (should ideally be 0).');
+        if InitCount <> 0 then
+          halt(1);
+end.