From fa19bfa239822379a4c06d4a42c992220f9aa6da 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. (cherry picked from commit 1298f5970b5056c5705bdce8c55719f5afbf52a4) --- 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 6ffb25ce1c..9ff3638986 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -587,6 +587,7 @@ Unix: - Fix wxIPaddress::Hostname() failing if /etc/hosts contained very long names. - Fix wxDateTime::ParseRfc822Date() for some TZ/DST combinations. +- Fix bug in wxExecute() if child exited too quickly (Kevin B. McCarty). All (GUI): diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp index 868d5e57d9..b23b770dd6 100644 --- a/src/unix/utilsunx.cpp +++ b/src/unix/utilsunx.cpp @@ -781,8 +781,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 @@ -834,17 +832,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. @@ -1628,9 +1633,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_)