From 1298f5970b5056c5705bdce8c55719f5afbf52a4 Mon Sep 17 00:00:00 2001 From: "Kevin B. McCarty" Date: Sat, 9 May 2015 19:28:04 +0200 Subject: [PATCH] Fix race condition in Unix wxExecute() if child exited too quickly. Check if the child has already finished before starting waiting for it. Closes #16661. --- docs/changes.txt | 1 + src/unix/utilsunx.cpp | 31 ++++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 4c82ec6c28..7e5beb2dbb 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -67,6 +67,7 @@ All: Unix: +- Fix bug in wxExecute() if child exited too quickly (Kevin B. McCarty). - Add --disable-sys-libs configure option. All (GUI): diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp index 3383e5cdf5..f7e63d2856 100644 --- a/src/unix/utilsunx.cpp +++ b/src/unix/utilsunx.cpp @@ -761,8 +761,6 @@ long wxExecute(char **argv, int flags, wxProcess *process, } else // we're in parent { - execData.OnStart(pid); - // prepare for IO redirection #if HAS_PIPE_STREAMS @@ -814,17 +812,24 @@ long wxExecute(char **argv, int flags, wxProcess *process, pipeErr.Close(); } - // For the asynchronous case we don't have to do anything else, just - // let the process run. if ( !(flags & wxEXEC_SYNC) ) { // Ensure that the housekeeping data is kept alive, it will be // destroyed only when the child terminates. execDataPtr.release(); - - return execData.pid; } + // Put the housekeeping data into the child process lookup table. + // Note that when running asynchronously, if the child has already + // finished this call will delete the execData and call any + // wxProcess's OnTerminate() handler immediately. + execData.OnStart(pid); + + // For the asynchronous case we don't have to do anything else, just + // let the process run (if not already finished). + if ( !(flags & wxEXEC_SYNC) ) + return pid; + // If we don't need to dispatch any events, things are relatively // simple and we don't need to delegate to wxAppTraits. @@ -1608,9 +1613,21 @@ void wxExecuteData::OnStart(int pid_) if ( process ) process->SetPid(pid); - // Finally, add this object itself to the list of child processes so that + // Add this object itself to the list of child processes so that // we can check for its termination the next time we get SIGCHLD. ms_childProcesses[pid] = this; + + // However, if the child exited before we finished setting up above, + // we may have already missed its SIGCHLD. So we also do an explicit + // check here before returning. + int exitcode; + if ( CheckForChildExit(pid, &exitcode) ) + { + // Handle its termination if it did. + // This call will implicitly remove it from ms_childProcesses + // and, if running asynchronously, it will delete itself. + OnExit(exitcode); + } } void wxExecuteData::OnExit(int exitcode_)