Forum > Beginners

[Beginner] Crash in TProcess Pipe access

(1/2) > >>

colo:
Dear Lazarus community,

I've started playing around with this nifty and very impressive language and IDE of yours, and tried to implement a little Windows GUI application to run external console programs with. I do not have any programming experience with either Windows nor Pasal/Delphi to speak of, and have some difficulty in assessing I am doing wrong about a runtime failure I experience, which is why I turn to you to ask for help.

I adapted some example code from the wiki and StackOverflow to have a child process running in the background with my application communication with it over its stdio descriptors. It seems like something during the execution goes wrong, and there might be some memory corruption involved. My x86 ASM is too limited to know what exactly is going on, but the memory address shown in the crash message does not look right to me.

My procedure:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---function RunExternalAppInMemo(AppPath: string; ArgV: TStringArray;  OutMemo: TMemo; ErrMemo: TMemo): integer;const  READ_BYTES = 2048;var  aProcess: TProcess;  NumBytes: longint;  Buffer: array of byte;  ErrBuffer: array of byte;  ReadCount: integer;  LastRead: longint;  ExitCode: integer;  i: integer; begin  Buffer := [];  ErrBuffer := [];  SetLength(Buffer, READ_BYTES + 1);  SetLength(ErrBuffer, READ_BYTES + 1);  LastRead := -1;  ExitCode := -1;  aProcess := TProcess.Create(nil);  aProcess.Executable := AppPath;  for i := 0 to Length(ArgV) - 1 do  begin    aProcess.Parameters.Add(ArgV[i]);    ErrMemo.Lines.Add(ArgV[i]);  end;  aProcess.ShowWindow := swoHIDE;  //aProcess.Options := aProcess.Options + [poUsePipes] + [poStdErrToOutput];  aProcess.Options := aProcess.Options + [poUsePipes];  try;    //ShowMessage(BoolToStr(aProcess.Running));    aProcess.Execute;    //ShowMessage(IntToStr(aProcess.Output.NumBytesAvailable));      while aProcess.Running or (aProcess.Output.NumBytesAvailable > 0) or      (aProcess.Stderr.NumBytesAvailable > 0) do    begin      while aProcess.Output.NumBytesAvailable > 0 do      begin        ReadCount := Min(READ_BYTES, aProcess.Output.NumBytesAvailable);        ShowMessage('Have bytes stdout: ' + IntToStr(aProcess.Output.NumBytesAvailable) + '  -  Will read stdout: ' + IntToStr(ReadCount));        ShowMessage('Have bytes stderr: ' + IntToStr(aProcess.Stderr.NumBytesAvailable));        LastRead := aProcess.Output.Read(Buffer, ReadCount);        if (LastRead = 0) then ShowMessage('Read 0 bytes, EOF?');        ShowMessage('Have read:' + IntToStr(LastRead));        // OutMemo.Lines.Append(PChar(Buffer)); // TODO: manage and eval buffer intellgently to get at logical lines or records of output to append        application.ProcessMessages;        ShowMessage('About to crash in NumBytesAvailable...');        ShowMessage('Have bytes stdout: ' + IntToStr(aProcess.Output.NumBytesAvailable));        ShowMessage('First iter end');      end;       while aProcess.Stderr.NumBytesAvailable > 0 do      begin        ReadCount := Min((READ_BYTES - 1), aProcess.Stderr.NumBytesAvailable);        aProcess.Stderr.Read(ErrBuffer, ReadCount);        ErrMemo.Lines.Add(PChar(ErrBuffer));        application.ProcessMessages;      end;      sleep(10);    end;    ExitCode := aProcess.ExitStatus;  finally    setlength(Buffer, 0);    setlength(ErrBuffer, 0);    aProcess.Free;  end;  Result := ExitCode;end; 
The crash message reads like this:
--- Quote ---Project ProcRun raised exception class 'External: ACCESS VIOLATION' with message: Access violation reading from address $FFFF...FFFF.
In file 'unit1.pas' at line 109: ShowMessage('Have bytes stdout' + IntToStr(aProcess.Output.NumBytesAvailable));
--- End quote ---

Interacting with the TProcess instance that seems to be executing my dependant process just fine after having read from aProcess.Output.Read seems to trigger the crash.

I have attached a contrived example of my code that should be able to demonstrate the failure on Windows hosts that can build it.

Can anyone please enlighten me what I am droing wrong? Any help - as well as tips on how to use the debugger to learn more about the underlyzing cause of this crash - would be greatly appreciated!

[Edited to fix code tags. Please read How to use the forum.]

marcov:

I don't see anything directly wrong, but it seems your original code is not based on 3.2.2 or trunk. You might want to see how it is now:

I'm not used to showmessage debugging though ( I usually debug to console or logfile without halting the process).

colo:
Thanks a lot for chiming in! :)


--- Quote from: marcov on May 01, 2022, 01:23:50 pm ---I don't see anything directly wrong, but it seems your original code is not based on 3.2.2 or trunk. You might want to see how it is now

--- End quote ---

Thanks for the pointer - my Lazarus IDE tells me that I am using FPC 3.2.2, so from a library/source code perspective, I should be OK, right? As for API usage, I've tried to stick to documented un-deprecated usage (such as steering away from TProcess.CommandLine). Since I still have some issues with consuming both Free Pascal source code and its usual documentation style, I'm not sure what difference in usage I should I aim for... if you could elaborate on that, I would be very grateful!



--- Quote from: marcov on May 01, 2022, 01:23:50 pm ---I'm not used to showmessage debugging though ( I usually debug to console or logfile without halting the process).

--- End quote ---

Me neiher :D But I haven't programmed a non-web GUI application in more than two decades, and that was the very first (and acceptably quick to implement) method that I could come up with. I am more familiar with workflows involving print() "debugging" and using an actual debugger (gdb, but outside of a full-blown IDE) on the shell, but since I'm in doubly unfamiliar territory (Pascal and Windows), I'm not sure what I even could expect. Is there a recommended introduction into effective debugging with the Lazarus IDE that I should consume?

marcov:
Meanwhile, I tested your code (with FPC 3.3.1, the only one that I have a lazarus for) and it doesn't crash.

I don't see any output however (while bytes were read)

ADDED later: I see the output memo is disabled, fixing that makes it work.

colo:
Huh, that is... unexpected? I tried to reproduce the crash now when compiling the same code (sans the unneeded, yet included, Windows-specifics that I bluntly ripped out to make it compile), and I get a SIGSEGV in very much the same way as I do get an exception on Windows 10. If I use it to invoke exeutable that do not have any stdio output (/bin/true, /bin/false) then it manages to run to completion. Still I am stumped to understand what is going on - if anyone on FPC 3.2.2 could try to reproduce, I'd be grateful.

I've tried to look for resources on how to integrate different FPC releases into Lazarus, but it's still unclear to me how to do that. Can anyon point me to the docs on how to swith the compiler used within Lazarus?

Navigation

[0] Message Index

[#] Next page

Go to full version