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

This commit is contained in:
Michaël Van Canneyt 2024-03-26 16:06:13 +01:00
parent ee1916e919
commit 564597a573
3 changed files with 26 additions and 14 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;