add a protection against large process output, close #424

This commit is contained in:
Basile Burg 2019-01-25 13:08:17 +01:00
parent 6e922954e8
commit c65592d659
5 changed files with 44 additions and 0 deletions

View File

@ -937,6 +937,7 @@ var
lst: TStringList; lst: TStringList;
str: string; str: string;
proc: TProcess; proc: TProcess;
dproc: TDexedProcess = nil;
begin begin
lst := TStringList.Create; lst := TStringList.Create;
try try
@ -956,9 +957,17 @@ begin
getprocInputHandler.removeProcess(TProcess(sender)); getprocInputHandler.removeProcess(TProcess(sender));
SetCurrentDirUTF8(fRunnerOldCwd); SetCurrentDirUTF8(fRunnerOldCwd);
if proc is TDexedProcess then
dproc := TDexedProcess(proc);
if (proc.ExitStatus <> 0) then if (proc.ExitStatus <> 0) then
begin
fMsgs.message(format('error: the process (%s) has returned the status %s', fMsgs.message(format('error: the process (%s) has returned the status %s',
[proc.Executable, prettyReturnStatus(proc)]), fAsProjectItf, amcProj, amkErr); [proc.Executable, prettyReturnStatus(proc)]), fAsProjectItf, amcProj, amkErr);
if dproc.isNotNil and dproc.autoKilled then
fMsgs.message(format('the process was autokilled because the size of its output exceeded %d',
[dproc.autoKillProcThreshold]), nil, amcProj, amkWarn);
end;
end; end;
end; end;

View File

@ -1060,6 +1060,9 @@ begin
dubCmd2PostMsg[fNextTerminatedCommand], fAsProjectItf, amcProj, amkWarn); dubCmd2PostMsg[fNextTerminatedCommand], fAsProjectItf, amcProj, amkWarn);
fMsgs.message(format('error: DUB has returned the status %s', fMsgs.message(format('error: DUB has returned the status %s',
[prettyReturnStatus(fDubProc)]), fAsProjectItf, amcProj, amkErr); [prettyReturnStatus(fDubProc)]), fAsProjectItf, amcProj, amkErr);
if fDubProc.autoKilled then
fMsgs.message(format('the process was autokilled because the size of its output exceeded %d',
[fDubProc.autoKillProcThreshold]), nil, amcProj, amkWarn);
end; end;
subjProjCompiled(fProjectSubject, fAsProjectItf, fCompiled); subjProjCompiled(fProjectSubject, fAsProjectItf, fCompiled);
SetCurrentDirUTF8(fPreCompilePath); SetCurrentDirUTF8(fPreCompilePath);

View File

@ -614,6 +614,7 @@ type
fAutoCheckUpdates: boolean; fAutoCheckUpdates: boolean;
fShowBuildDuration: boolean; fShowBuildDuration: boolean;
fToolBarScaling: TToolBarScaling; fToolBarScaling: TToolBarScaling;
fAutoKillProcThreshold: dword;
function getConsoleProgram: string; function getConsoleProgram: string;
procedure setConsoleProgram(const value: string); procedure setConsoleProgram(const value: string);
function getAdditionalPATH: string; function getAdditionalPATH: string;
@ -624,6 +625,7 @@ type
published published
property additionalPATH: string read getAdditionalPATH write setAdditionalPath; property additionalPATH: string read getAdditionalPATH write setAdditionalPath;
property autoCheckUpdates: boolean read fAutoCheckUpdates write fAutoCheckUpdates; property autoCheckUpdates: boolean read fAutoCheckUpdates write fAutoCheckUpdates;
property autoKillProcThreshold: dword read fAutoKillProcThreshold write fAutoKillProcThreshold default 1024 * 1024 * 2;
property consoleProgram: string read getConsoleProgram write setConsoleProgram; property consoleProgram: string read getConsoleProgram write setConsoleProgram;
property coverModuleTests: boolean read fCovModUt write fCovModUt; property coverModuleTests: boolean read fCovModUt write fCovModUt;
property floatingWidgetOnTop: boolean read fFloatingWidgetOnTop write fFloatingWidgetOnTop; property floatingWidgetOnTop: boolean read fFloatingWidgetOnTop write fFloatingWidgetOnTop;
@ -839,6 +841,7 @@ begin
fReloadLastDocuments:=true; fReloadLastDocuments:=true;
fFlatLook:=true; fFlatLook:=true;
fDcdPort:=DCDWrapper.port; fDcdPort:=DCDWrapper.port;
fAutoKillProcThreshold := 1024 * 1024 * 2;
end; end;
function TApplicationOptionsBase.getNativeProjecCompiler: DCompiler; function TApplicationOptionsBase.getNativeProjecCompiler: DCompiler;
@ -929,6 +932,7 @@ begin
MainForm.fDscanUnittests := fDscanUnittests; MainForm.fDscanUnittests := fDscanUnittests;
nativeProjectCompiler:= fBackup.nativeProjectCompiler; nativeProjectCompiler:= fBackup.nativeProjectCompiler;
fToolBarScaling:= fBackup.fToolBarScaling; fToolBarScaling:= fBackup.fToolBarScaling;
fAutoKillProcThreshold:= fBackup.fAutoKillProcThreshold;
end end
else inherited; else inherited;
end; end;
@ -945,6 +949,7 @@ begin
MainForm.fPrjGrpMru.maxCount:= fMaxRecentGroups; MainForm.fPrjGrpMru.maxCount:= fMaxRecentGroups;
MainForm.updateFloatingWidgetOnTop(fFloatingWidgetOnTop); MainForm.updateFloatingWidgetOnTop(fFloatingWidgetOnTop);
MainForm.fDscanUnittests := fDscanUnittests; MainForm.fDscanUnittests := fDscanUnittests;
TDexedProcess.autoKillProcThreshold:= fAutoKillProcThreshold;
DcdWrapper.port:=fDcdPort; DcdWrapper.port:=fDcdPort;
for i := 0 to MainForm.fWidgList.Count-1 do for i := 0 to MainForm.fWidgList.Count-1 do
begin begin
@ -968,6 +973,7 @@ begin
fBackup.fAutoCheckUpdates:= fAutoCheckUpdates; fBackup.fAutoCheckUpdates:= fAutoCheckUpdates;
fBackup.fShowBuildDuration:= fShowBuildDuration; fBackup.fShowBuildDuration:= fShowBuildDuration;
fBackup.nativeProjectCompiler:= nativeProjectCompiler; fBackup.nativeProjectCompiler:= nativeProjectCompiler;
fBackup.fAutoKillProcThreshold := fAutoKillProcThreshold;
end end
else inherited; else inherited;
end; end;
@ -2978,8 +2984,13 @@ begin
if inph.isNotNil then if inph.isNotNil then
(inph as IProcInputHandler).removeProcess(proc); (inph as IProcInputHandler).removeProcess(proc);
if (proc.ExitStatus <> 0) then if (proc.ExitStatus <> 0) then
begin
fMsgs.message(format('error: the process (%s) has returned the status %s', fMsgs.message(format('error: the process (%s) has returned the status %s',
[proc.Executable, prettyReturnStatus(proc)]), fDoc, amcEdit, amkErr); [proc.Executable, prettyReturnStatus(proc)]), fDoc, amcEdit, amkErr);
if proc.autoKilled then
fMsgs.message(format('the process was autokilled because the size of its output exceeded %d',
[proc.autoKillProcThreshold]), nil, amcEdit, amkWarn);
end;
end; end;
procedure TMainForm.actSetRunnableSwExecute(Sender: TObject); procedure TMainForm.actSetRunnableSwExecute(Sender: TObject);

View File

@ -32,6 +32,8 @@ type
} }
TDexedProcess = class(TASyncProcess) TDexedProcess = class(TASyncProcess)
private private
class var FAutoKillProcThreshold: dword;
var
fErrToOut: boolean; fErrToOut: boolean;
fRealOnTerminate: TNotifyEvent; fRealOnTerminate: TNotifyEvent;
fRealOnReadData: TNotifyEvent; fRealOnReadData: TNotifyEvent;
@ -40,6 +42,7 @@ type
fTerminateChecker: TTimer; fTerminateChecker: TTimer;
fDoneTerminated: boolean; fDoneTerminated: boolean;
fHasRead: boolean; fHasRead: boolean;
fAutoKilled: boolean;
procedure checkTerminated(sender: TObject); procedure checkTerminated(sender: TObject);
procedure setOnTerminate(value: TNotifyEvent); procedure setOnTerminate(value: TNotifyEvent);
procedure setOnReadData(value: TNotifyEvent); procedure setOnReadData(value: TNotifyEvent);
@ -65,6 +68,10 @@ type
property hasRead: boolean read fHasRead; property hasRead: boolean read fHasRead;
// indicates if OnTerminated was called // indicates if OnTerminated was called
property doneTerminated: boolean read fDoneTerminated; property doneTerminated: boolean read fDoneTerminated;
// indicates of the process was autokilled
property autoKilled: boolean read fAutoKilled;
// auto kill the process if its output reach this size
class property autoKillProcThreshold: dword read FAutoKillProcThreshold write FAutoKillProcThreshold;
end; end;
{ {
@ -188,6 +195,7 @@ end;
procedure TDexedProcess.Execute; procedure TDexedProcess.Execute;
begin begin
fAutoKilled := false;
fHasRead := false; fHasRead := false;
fStdoutEx.Clear; fStdoutEx.Clear;
fStderrEx.Clear; fStderrEx.Clear;
@ -214,6 +222,16 @@ procedure TDexedProcess.fillOutputStack;
outStr.SetSize(s + 1024); outStr.SetSize(s + 1024);
c := inStr.Read((outStr.Memory + s)^, 1024); c := inStr.Read((outStr.Memory + s)^, 1024);
s += c; s += c;
if (FAutoKillProcThreshold <> 0) and not fDoneTerminated and
(fStderrEx.Size + fStdoutEx.Size >= FAutoKillProcThreshold) then
begin
fStdoutEx.Clear;
fAutoKilled := true;
Terminate(1);
exit;
end;
end; end;
outStr.SetSize(s); outStr.SetSize(s);
end; end;

View File

@ -272,6 +272,9 @@ begin
begin begin
fMsgs.message(format('error: the tool (%s) has returned the status %s', fMsgs.message(format('error: the tool (%s) has returned the status %s',
[fProcess.Executable, prettyReturnStatus(fProcess)]), nil, amcMisc, amkErr); [fProcess.Executable, prettyReturnStatus(fProcess)]), nil, amcMisc, amkErr);
if fProcess.autoKilled then
fMsgs.message(format('the process was autokilled because the size of its output exceeded %d',
[fProcess.autoKillProcThreshold]), nil, amcMisc, amkWarn);
u_processes.killProcess(fProcess); u_processes.killProcess(fProcess);
exit; exit;
end end