Răsfoiți Sursa

* Fix access violation: module can be reset while loading dependent units. Fixes issue #40705

Michaël Van Canneyt 1 an în urmă
părinte
comite
564597a573
3 a modificat fișierele cu 26 adăugiri și 14 ștergeri
  1. 4 0
      compiler/ctask.pas
  2. 7 2
      compiler/fppu.pas
  3. 15 12
      compiler/pmodules.pas

+ 4 - 0
compiler/ctask.pas

@@ -368,6 +368,9 @@ begin
   e:=ttask_list(Hash.Find(n));
   if e=nil then
     begin
+    // Clear reset flag.
+    // This can happen when during load, reset is done and unit is added to task list.
+    m.is_reset:=false;
     t:=ttask_list.create(m);
     list.insert(t);
     hash.Add(n,t);
@@ -379,6 +382,7 @@ begin
     // We have a task, if it was reset, then clear the state and move the task to the start.
     if m.is_reset then
       begin
+      {$IFDEF DEBUG_CTASK}Writeln(m.ToString,' was reset, resetting flag. State: ',m.state);{$ENDIF}
       m.is_reset:=false;
       t:=findtask(m);
       if assigned(t) then

+ 7 - 2
compiler/fppu.pas

@@ -2174,6 +2174,12 @@ var
 
       procedure tppumodule.prepare_second_load(from_module: tmodule);
 
+      const
+         CompileStates  = [ms_compile, ms_compiling_waitintf, ms_compiling_waitimpl,
+                           ms_compiling_waitfinish, ms_compiling_wait, ms_compiled,
+                           ms_processed];
+
+
         begin
           { try to load the unit a second time first }
           Message1(unit_u_second_load_unit,modulename^);
@@ -2182,7 +2188,7 @@ var
           flagdependent(from_module);
           { Reset the module }
           reset;
-          if state in [ms_compile] then
+          if state in CompileStates then
             begin
               Message1(unit_u_second_compile_unit,modulename^);
               state:=ms_compile;
@@ -2253,7 +2259,6 @@ var
         flagdependent(from_module);
         { Reset the module }
         reset;
-        is_reset:=false;
         { mark this module for recompilation }
         if not (state in [ms_compile]) then
           state:=ms_compile;

+ 15 - 12
compiler/pmodules.pas

@@ -559,6 +559,7 @@ implementation
          filepos : tfileposinfo;
          isnew : boolean;
 
+
       begin
         consume(_USES);
         repeat
@@ -640,6 +641,7 @@ implementation
          state: tglobalstate;
          isLoaded : Boolean;
          mwait : tmodule;
+         lu : tmodule;
 
          procedure restorestate;
 
@@ -650,7 +652,6 @@ implementation
               if assigned(current_scanner.inputfile) then
                 current_scanner.tempopeninputfile;
               end;
-
            state.free;
          end;
 
@@ -663,35 +664,37 @@ implementation
          pu:=tused_unit(curr.used_units.first);
          while assigned(pu) do
           begin
+            lu:=pu.u;
             { Only load the units that are in the current
               (interface/implementation) uses clause }
             if pu.in_uses and
                (pu.in_interface=frominterface) then
              begin
-               if (pu.u.state in [ms_processed, ms_compiled,ms_compiling_waitimpl]) then
+               if (lu.state in [ms_processed, ms_compiled,ms_compiling_waitimpl]) then
                  isLoaded:=true
-               else if (pu.u.state=ms_registered) then
+               else if (lu.state=ms_registered) then
                   // try to load
-                 isLoaded:=tppumodule(pu.u).loadppu(curr)
+                 isLoaded:=tppumodule(lu).loadppu(curr)
                else
                  isLoaded:=False;
-               isLoaded:=IsLoaded and not pu.u.is_reset;
+               isLoaded:=IsLoaded and not lu.is_reset ;
                if not IsLoaded then
                  begin
                    if mwait=nil then
-                     mwait:=pu.u;
+                     mwait:=lu;
                    // In case of is_reset, the task handler will discard the state if the module was already there
-                   task_handler.addmodule(pu.u);
+                   task_handler.addmodule(lu);
                  end;
+               IsLoaded:=Isloaded and not curr.is_reset;
                Result:=Result and IsLoaded;
+               { If we were reset, then used_units is no longer correct, and we must exit at once. }
+               if curr.is_reset then
+                 break;
                { is our module compiled? then we can stop }
                if curr.state in [ms_compiled,ms_processed] then
-                 begin
-                 Restorestate;
-                 exit;
-                 end;
+                 break;
                { add this unit to the dependencies }
-               pu.u.adddependency(curr,frominterface);
+               lu.adddependency(curr,frominterface);
                { check hints }
                pu.check_hints;
              end;