ソースを参照

* avoid writing the stabs for a child class before those of a parent
class in case the parent class has a field with as type the (forward
defined) child class, because this crashes gdb
+ (interactive) test for this

git-svn-id: trunk@8565 -

Jonas Maebe 18 年 前
コミット
9049f845f4
4 ファイル変更72 行追加3 行削除
  1. 1 0
      .gitattributes
  2. 25 2
      compiler/dbgstabs.pas
  3. 2 1
      compiler/symconst.pas
  4. 44 0
      tests/webtbs/tw9766.pp

+ 1 - 0
.gitattributes

@@ -8456,6 +8456,7 @@ tests/webtbs/tw9385.pp svneol=native#text/plain
 tests/webtbs/tw9672.pp svneol=native#text/plain
 tests/webtbs/tw9695.pp svneol=native#text/plain
 tests/webtbs/tw9704.pp svneol=native#text/plain
+tests/webtbs/tw9766.pp svneol=native#text/plain
 tests/webtbs/ub1873.pp svneol=native#text/plain
 tests/webtbs/ub1883.pp svneol=native#text/plain
 tests/webtbs/uw0555.pp svneol=native#text/plain

+ 25 - 2
compiler/dbgstabs.pas

@@ -271,7 +271,7 @@ implementation
 
         { Stab must already be written, or we must be busy writing it }
         if writing_def_stabs and
-           not(def.dbg_state in [dbg_state_writing,dbg_state_written]) then
+           not(def.dbg_state in [dbg_state_writing,dbg_state_written,dbg_state_queued]) then
           internalerror(200403091);
 
         { Keep track of used stabs, this info is only usefull for stabs
@@ -904,6 +904,29 @@ implementation
               insertdef(list,tenumdef(def).basedef);
           objectdef :
             begin
+              { make sure we don't write child classdefs before their parent }
+              { classdefs, because this crashes gdb                          }
+              anc:=tobjectdef(def);
+              while assigned(anc.childof) do
+                begin
+                  anc:=anc.childof;
+                  if (anc.dbg_state=dbg_state_writing) then
+                    { happens in case a field of a parent is of the (forward }
+                    { defined) child type                                    }
+                    begin
+                      { We don't explicitly requeue it, but the fact that  }
+                      { a child type was used in a parent before the child }
+                      { type was fully defined means that it was forward   }
+                      { declared, and will still be encountered later (it  }
+                      { cannot have been declared in another unit, because }
+                      { then this and that other unit would depend on      }
+                      { eachother's interface)                             }
+                      { Setting the state to queued however allows us to   }
+                      { get the def number already without an IE           }
+                      def.dbg_state:=dbg_state_queued;
+                      exit;
+                    end;
+                end;
               insertdef(list,vmtarraytype);
               if assigned(tobjectdef(def).ImplementedInterfaces) then
                 for i:=0 to tobjectdef(def).ImplementedInterfaces.Count-1 do
@@ -970,7 +993,7 @@ implementation
            for i:=0 to st.DefList.Count-1 do
              begin
                def:=tdef(st.DefList[i]);
-               if (def.dbg_state=dbg_state_used) then
+               if (def.dbg_state in [dbg_state_used,dbg_state_queued]) then
                  insertdef(list,def);
              end;
          end;

+ 2 - 1
compiler/symconst.pas

@@ -463,7 +463,8 @@ type
     dbg_state_unused,
     dbg_state_used,
     dbg_state_writing,
-    dbg_state_written
+    dbg_state_written,
+    dbg_state_queued
   );
 
 

+ 44 - 0
tests/webtbs/tw9766.pp

@@ -0,0 +1,44 @@
+{ %interactive }
+
+{ instructions: set a breakpoint on PASCALMAIN, then step into }
+{ TChild.Create(nil). This shouldn't crash gdb                 }
+
+{$mode delphi}
+
+type
+  // swap the order of these declarations (TParent & TChild) and the problem is fixed.
+  TParent = class;
+  TChild = class;
+
+  TParent = class
+  private
+    FChild : TChild; // remove me and the problem is fixed.
+  public
+    constructor Create ( AOwner : pointer ); virtual;
+  end;
+
+  TChild = class(TParent)
+  private
+    FField : Integer; // remove me and the problem is fixed.
+  public
+    constructor Create ( AOwner : pointer ); override;
+  end;
+
+{ TParent }
+
+constructor TParent.Create(AOwner: pointer);
+begin
+  Inherited Create;
+end;
+
+{ TChild }
+
+constructor TChild.Create(AOwner: pointer);
+begin
+  Inherited;
+end;
+
+
+begin
+  TChild.Create(nil); // break-point here and try to step into constructor (gdb/stabs)
+end.