Ensure that all FH are closed and the subprocess is reaped upon System::Command object destruction. #31
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
IO objects are special, and sometimes are not destroyed when references to them disappear.
Here's some example code (for real code to run and exhibit the unwanted behavior, see below)
When the block ends,
$cmdwill be destroyed. Sometimes the order of destruction isSystem::CommandIO::HandleSystem::Command::Reaperand sometimes it is
System::CommandSystem::Command::ReaperExperimentally, when the
Reaperobject is destroyed (regardless of whether the IO::Handles are destroyed first) it has lost access to its cachedIO::Handleobjects. They are cached as weak references, and when theCommandobject is destroyed, it releases its references to them, and the Reaper object loses its references.If the second order of destruction happens, the handles still exist (Perl seems to have an internal cache for them), but
Reaperdoesn't see them, and thus can't close them. It will try to reap the child process, but if the child is awaiting input, it will never exit, cannot be reaped, andReaper::_reapwill hang forever.(Note that explicitly closing the handles via
$cmd->closeis not safe, as, if the program is interrupted before the close, and the signal handler throws, e.g.$SIG{INT} = sub { die }, the$cmd->closedoes not get fired.A bit further below is some real test code. Run it as, e.g.,
In the above example, the last instance hangs because the
stdinIO::Handlehasn't been destroyed.It may need a few iterations to trigger the bug.