Backport fixes for rhbz1373197, attach thread races.
This commit is contained in:
parent
eafaeab37f
commit
211f9c452c
526
dyninst-9.2.0-proccontrol-thread-races.patch
Normal file
526
dyninst-9.2.0-proccontrol-thread-races.patch
Normal file
@ -0,0 +1,526 @@
|
|||||||
|
Backported fixes for rhbz1373197 / issue208
|
||||||
|
* https://bugzilla.redhat.com/show_bug.cgi?id=1373197
|
||||||
|
* https://github.com/dyninst/dyninst/issues/208
|
||||||
|
|
||||||
|
* https://github.com/dyninst/dyninst/pull/212
|
||||||
|
* https://github.com/dyninst/dyninst/pull/214
|
||||||
|
* https://github.com/dyninst/dyninst/pull/259
|
||||||
|
* https://github.com/dyninst/dyninst/pull/261
|
||||||
|
|
||||||
|
|
||||||
|
commit 251b5549217f716c5ad11509417b3f780d54114c
|
||||||
|
Author: Matthew LeGendre <legendre1@llnl.gov>
|
||||||
|
Date: Tue Oct 25 16:13:05 2016 -0700
|
||||||
|
|
||||||
|
Fix errors when thread disappears during attach
|
||||||
|
|
||||||
|
diff --git a/proccontrol/src/linux.C b/proccontrol/src/linux.C
|
||||||
|
index 4502e357f79f..c55295d836ed 100644
|
||||||
|
--- a/proccontrol/src/linux.C
|
||||||
|
+++ b/proccontrol/src/linux.C
|
||||||
|
@@ -1012,17 +1012,28 @@ bool linux_process::plat_getOSRunningStates(std::map<Dyninst::LWP, bool> &runnin
|
||||||
|
snprintf(proc_stat_name, 128, "/proc/%d/stat", *i);
|
||||||
|
FILE *sfile = fopen(proc_stat_name, "r");
|
||||||
|
|
||||||
|
- if (sfile == NULL) {
|
||||||
|
+ if (*i == getPid() && sfile == NULL) {
|
||||||
|
pthrd_printf("Failed to open /proc/%d/stat file\n", *i);
|
||||||
|
setLastError(err_noproc, "Failed to find /proc files for debuggee");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
- if( fread(sstat, 1, 256, sfile) == 0 ) {
|
||||||
|
+ else if (sfile == NULL) {
|
||||||
|
+ //thread died between the above getThreadLWPs and the /proc/pid/stat open
|
||||||
|
+ // just drop it from the to-attach list.
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ size_t result = fread(sstat, 1, 256, sfile);
|
||||||
|
+ if (*i == getPid() && result == 0) {
|
||||||
|
pthrd_printf("Failed to read /proc/%d/stat file \n", *i);
|
||||||
|
setLastError(err_noproc, "Failed to find /proc files for debuggee");
|
||||||
|
fclose(sfile);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
+ else if (result == 0) {
|
||||||
|
+ fclose(sfile);
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
fclose(sfile);
|
||||||
|
|
||||||
|
sstat[255] = '\0';
|
||||||
|
|
||||||
|
commit 6c690a487a18798dac1bf663e027a3e21354418a
|
||||||
|
Author: Josh Stone <jistone@redhat.com>
|
||||||
|
Date: Fri Oct 28 18:09:16 2016 -0700
|
||||||
|
|
||||||
|
proccontrol: refactor plat_getOSRunningStates
|
||||||
|
|
||||||
|
- The file is now opened with ifstream for RAII.
|
||||||
|
- The former paren_level logic is removed to instead scan for ") R ".
|
||||||
|
(If there were parens in the command, they might not be balanced!)
|
||||||
|
|
||||||
|
diff --git a/proccontrol/src/linux.C b/proccontrol/src/linux.C
|
||||||
|
index c55295d836ed..56ac407bad1c 100644
|
||||||
|
--- a/proccontrol/src/linux.C
|
||||||
|
+++ b/proccontrol/src/linux.C
|
||||||
|
@@ -40,6 +40,7 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <iostream>
|
||||||
|
+#include <fstream>
|
||||||
|
|
||||||
|
#include "common/h/dyn_regs.h"
|
||||||
|
#include "common/h/dyntypes.h"
|
||||||
|
@@ -1004,51 +1005,38 @@ bool linux_process::plat_getOSRunningStates(std::map<Dyninst::LWP, bool> &runnin
|
||||||
|
for(vector<Dyninst::LWP>::iterator i = lwps.begin();
|
||||||
|
i != lwps.end(); ++i)
|
||||||
|
{
|
||||||
|
+ const auto ignore_max = std::numeric_limits<std::streamsize>::max();
|
||||||
|
char proc_stat_name[128];
|
||||||
|
- char sstat[256];
|
||||||
|
- char *status;
|
||||||
|
- int paren_level = 1;
|
||||||
|
|
||||||
|
snprintf(proc_stat_name, 128, "/proc/%d/stat", *i);
|
||||||
|
- FILE *sfile = fopen(proc_stat_name, "r");
|
||||||
|
+ ifstream sfile(proc_stat_name);
|
||||||
|
|
||||||
|
- if (*i == getPid() && sfile == NULL) {
|
||||||
|
- pthrd_printf("Failed to open /proc/%d/stat file\n", *i);
|
||||||
|
- setLastError(err_noproc, "Failed to find /proc files for debuggee");
|
||||||
|
- return false;
|
||||||
|
- }
|
||||||
|
- else if (sfile == NULL) {
|
||||||
|
- //thread died between the above getThreadLWPs and the /proc/pid/stat open
|
||||||
|
- // just drop it from the to-attach list.
|
||||||
|
- continue;
|
||||||
|
- }
|
||||||
|
- size_t result = fread(sstat, 1, 256, sfile);
|
||||||
|
- if (*i == getPid() && result == 0) {
|
||||||
|
- pthrd_printf("Failed to read /proc/%d/stat file \n", *i);
|
||||||
|
- setLastError(err_noproc, "Failed to find /proc files for debuggee");
|
||||||
|
- fclose(sfile);
|
||||||
|
- return false;
|
||||||
|
- }
|
||||||
|
- else if (result == 0) {
|
||||||
|
- fclose(sfile);
|
||||||
|
- continue;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- fclose(sfile);
|
||||||
|
+ while (sfile.good()) {
|
||||||
|
|
||||||
|
- sstat[255] = '\0';
|
||||||
|
- status = sstat;
|
||||||
|
+ // The stat looks something like: 123 (command) R 456...
|
||||||
|
+ // We'll just look for the ") R " part.
|
||||||
|
+ if (sfile.ignore(ignore_max, ')').peek() == ' ') {
|
||||||
|
+ char space, state;
|
||||||
|
|
||||||
|
- while (*status != '\0' && *(status++) != '(') ;
|
||||||
|
- while (*status != '\0' && paren_level != 0) {
|
||||||
|
- if (*status == '(') paren_level++;
|
||||||
|
- if (*status == ')') paren_level--;
|
||||||
|
- status++;
|
||||||
|
- }
|
||||||
|
+ // Eat the space we peeked and grab the state char.
|
||||||
|
+ if (sfile.get(space).get(state).peek() == ' ') {
|
||||||
|
+ // Found the state char -- 'T' means it's already stopped.
|
||||||
|
+ runningStates.insert(make_pair(*i, (state != 'T')));
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- while (*status == ' ') status++;
|
||||||
|
+ // Restore the state char and try again
|
||||||
|
+ sfile.unget();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- runningStates.insert(make_pair(*i, (*status != 'T')));
|
||||||
|
+ if (!sfile.good() && (*i == getPid())) {
|
||||||
|
+ // Only the main thread is treated as an error. Other threads may
|
||||||
|
+ // have exited between getThreadLWPs and /proc/pid/stat open or read.
|
||||||
|
+ pthrd_printf("Failed to read /proc/%d/stat file\n", *i);
|
||||||
|
+ setLastError(err_noproc, "Failed to find /proc files for debuggee");
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
commit f95c058505eb606e0e2f0ce47d0dcf6990bc41ff
|
||||||
|
Author: Josh Stone <jistone@redhat.com>
|
||||||
|
Date: Fri Nov 4 18:31:28 2016 -0700
|
||||||
|
|
||||||
|
proccontrol: Synchronize additional threads found during attach
|
||||||
|
|
||||||
|
When additional threads are found during the attach process, we should
|
||||||
|
synchronize to their stopping point, and check for new threads again,
|
||||||
|
until no new threads are found. This keeps a more consistent state if
|
||||||
|
threads are racing to start while we're attaching.
|
||||||
|
|
||||||
|
diff --git a/proccontrol/src/int_process.h b/proccontrol/src/int_process.h
|
||||||
|
index f389175a0a13..20a8648a79ea 100644
|
||||||
|
--- a/proccontrol/src/int_process.h
|
||||||
|
+++ b/proccontrol/src/int_process.h
|
||||||
|
@@ -271,7 +271,9 @@ class int_process
|
||||||
|
static bool reattach(int_processSet *pset);
|
||||||
|
virtual bool plat_attach(bool allStopped, bool &should_sync) = 0;
|
||||||
|
|
||||||
|
+ bool attachThreads(bool &found_new_threads);
|
||||||
|
bool attachThreads();
|
||||||
|
+ bool attachThreadsSync();
|
||||||
|
virtual async_ret_t post_attach(bool wasDetached, std::set<response::ptr> &aresps);
|
||||||
|
async_ret_t initializeAddressSpace(std::set<response::ptr> &async_responses);
|
||||||
|
|
||||||
|
diff --git a/proccontrol/src/process.C b/proccontrol/src/process.C
|
||||||
|
index d231e9ee6d36..c6b0dad80e25 100644
|
||||||
|
--- a/proccontrol/src/process.C
|
||||||
|
+++ b/proccontrol/src/process.C
|
||||||
|
@@ -211,8 +211,10 @@ void int_process::plat_threadAttachDone()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
-bool int_process::attachThreads()
|
||||||
|
+bool int_process::attachThreads(bool &found_new_threads)
|
||||||
|
{
|
||||||
|
+ found_new_threads = false;
|
||||||
|
+
|
||||||
|
if (!needIndividualThreadAttach())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
@@ -224,9 +226,9 @@ bool int_process::attachThreads()
|
||||||
|
* a list of LWPs, but then new threads are created before we attach to
|
||||||
|
* all the existing threads.
|
||||||
|
**/
|
||||||
|
- bool found_new_threads;
|
||||||
|
+ bool loop_new_threads;
|
||||||
|
do {
|
||||||
|
- found_new_threads = false;
|
||||||
|
+ loop_new_threads = false;
|
||||||
|
vector<Dyninst::LWP> lwps;
|
||||||
|
bool result = getThreadLWPs(lwps);
|
||||||
|
if (!result) {
|
||||||
|
@@ -242,13 +244,56 @@ bool int_process::attachThreads()
|
||||||
|
}
|
||||||
|
pthrd_printf("Creating new thread for %d/%d during attach\n", pid, *i);
|
||||||
|
thr = int_thread::createThread(this, NULL_THR_ID, *i, false, int_thread::as_needs_attach);
|
||||||
|
- found_new_threads = true;
|
||||||
|
+ found_new_threads = loop_new_threads = true;
|
||||||
|
}
|
||||||
|
- } while (found_new_threads);
|
||||||
|
+ } while (loop_new_threads);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+bool int_process::attachThreads()
|
||||||
|
+{
|
||||||
|
+ bool found_new_threads = false;
|
||||||
|
+ return attachThreads(found_new_threads);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// Attach any new threads and synchronize, until there are no new threads
|
||||||
|
+bool int_process::attachThreadsSync()
|
||||||
|
+{
|
||||||
|
+ while (true) {
|
||||||
|
+ bool found_new_threads = false;
|
||||||
|
+
|
||||||
|
+ ProcPool()->condvar()->lock();
|
||||||
|
+ bool result = attachThreads(found_new_threads);
|
||||||
|
+ if (found_new_threads)
|
||||||
|
+ ProcPool()->condvar()->broadcast();
|
||||||
|
+ ProcPool()->condvar()->unlock();
|
||||||
|
+
|
||||||
|
+ if (!result) {
|
||||||
|
+ pthrd_printf("Failed to attach to threads in %d\n", pid);
|
||||||
|
+ setLastError(err_internal, "Could not get threads during attach\n");
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!found_new_threads)
|
||||||
|
+ return true;
|
||||||
|
+
|
||||||
|
+ pthrd_printf("Wait again for attach from process %d\n", pid);
|
||||||
|
+ bool proc_exited = false;
|
||||||
|
+ result = waitAndHandleForProc(true, this, proc_exited);
|
||||||
|
+ if (!result) {
|
||||||
|
+ perr_printf("Internal error calling waitAndHandleForProc on %d\n", getPid());
|
||||||
|
+ setLastError(err_internal, "Error while calling waitAndHandleForProc for attached threads\n");
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ if (proc_exited) {
|
||||||
|
+ perr_printf("Process exited while waiting for user thread stop, erroring\n");
|
||||||
|
+ setLastError(err_exited, "Process exited while thread being stopped.\n");
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
bool int_process::attach(int_processSet *ps, bool reattach)
|
||||||
|
{
|
||||||
|
bool had_error = false, should_sync = false;
|
||||||
|
@@ -443,10 +488,9 @@ bool int_process::attach(int_processSet *ps, bool reattach)
|
||||||
|
int_process *proc = *i;
|
||||||
|
if (proc->getState() == errorstate)
|
||||||
|
continue;
|
||||||
|
- bool result = proc->attachThreads();
|
||||||
|
+ bool result = proc->attachThreadsSync();
|
||||||
|
if (!result) {
|
||||||
|
pthrd_printf("Failed to attach to threads in %d--now an error\n", proc->pid);
|
||||||
|
- proc->setLastError(err_internal, "Could not get threads during attach\n");
|
||||||
|
procs.erase(i++);
|
||||||
|
had_error = true;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
commit 7041993caa9d022eac7b17018ddd3daa5cfe0696
|
||||||
|
Author: Josh Stone <jistone@redhat.com>
|
||||||
|
Date: Wed Nov 9 18:13:28 2016 -0800
|
||||||
|
|
||||||
|
proccontrol: move thread sync to linux_process, and count neonatal
|
||||||
|
|
||||||
|
diff --git a/proccontrol/src/int_process.h b/proccontrol/src/int_process.h
|
||||||
|
index 20a8648a79ea..0c292f297b2a 100644
|
||||||
|
--- a/proccontrol/src/int_process.h
|
||||||
|
+++ b/proccontrol/src/int_process.h
|
||||||
|
@@ -273,7 +273,8 @@ class int_process
|
||||||
|
|
||||||
|
bool attachThreads(bool &found_new_threads);
|
||||||
|
bool attachThreads();
|
||||||
|
- bool attachThreadsSync();
|
||||||
|
+ virtual bool plat_attachThreadsSync();
|
||||||
|
+
|
||||||
|
virtual async_ret_t post_attach(bool wasDetached, std::set<response::ptr> &aresps);
|
||||||
|
async_ret_t initializeAddressSpace(std::set<response::ptr> &async_responses);
|
||||||
|
|
||||||
|
diff --git a/proccontrol/src/linux.C b/proccontrol/src/linux.C
|
||||||
|
index 56ac407bad1c..f230967af034 100644
|
||||||
|
--- a/proccontrol/src/linux.C
|
||||||
|
+++ b/proccontrol/src/linux.C
|
||||||
|
@@ -1113,6 +1113,44 @@ bool linux_process::plat_attach(bool, bool &)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+// Attach any new threads and synchronize, until there are no new threads
|
||||||
|
+bool linux_process::plat_attachThreadsSync()
|
||||||
|
+{
|
||||||
|
+ while (true) {
|
||||||
|
+ bool found_new_threads = false;
|
||||||
|
+
|
||||||
|
+ ProcPool()->condvar()->lock();
|
||||||
|
+ bool result = attachThreads(found_new_threads);
|
||||||
|
+ if (found_new_threads)
|
||||||
|
+ ProcPool()->condvar()->broadcast();
|
||||||
|
+ ProcPool()->condvar()->unlock();
|
||||||
|
+
|
||||||
|
+ if (!result) {
|
||||||
|
+ pthrd_printf("Failed to attach to threads in %d\n", pid);
|
||||||
|
+ setLastError(err_internal, "Could not get threads during attach\n");
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!found_new_threads)
|
||||||
|
+ return true;
|
||||||
|
+
|
||||||
|
+ while (Counter::processCount(Counter::NeonatalThreads, this) > 0) {
|
||||||
|
+ bool proc_exited = false;
|
||||||
|
+ pthrd_printf("Waiting for neonatal threads in process %d\n", pid);
|
||||||
|
+ result = waitAndHandleForProc(true, this, proc_exited);
|
||||||
|
+ if (!result) {
|
||||||
|
+ perr_printf("Internal error calling waitAndHandleForProc on %d\n", getPid());
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ if (proc_exited) {
|
||||||
|
+ perr_printf("Process exited while waiting for user thread stop, erroring\n");
|
||||||
|
+ setLastError(err_exited, "Process exited while thread being stopped.\n");
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
bool linux_process::plat_attachWillTriggerStop() {
|
||||||
|
char procName[64];
|
||||||
|
char cmd[256];
|
||||||
|
diff --git a/proccontrol/src/linux.h b/proccontrol/src/linux.h
|
||||||
|
index 4972fb71143f..56326ad9e6a8 100644
|
||||||
|
--- a/proccontrol/src/linux.h
|
||||||
|
+++ b/proccontrol/src/linux.h
|
||||||
|
@@ -111,6 +111,7 @@ class linux_process : public sysv_process, public unix_process, public thread_db
|
||||||
|
virtual bool plat_create();
|
||||||
|
virtual bool plat_create_int();
|
||||||
|
virtual bool plat_attach(bool allStopped, bool &);
|
||||||
|
+ virtual bool plat_attachThreadsSync();
|
||||||
|
virtual bool plat_attachWillTriggerStop();
|
||||||
|
virtual bool plat_forked();
|
||||||
|
virtual bool plat_execed();
|
||||||
|
diff --git a/proccontrol/src/process.C b/proccontrol/src/process.C
|
||||||
|
index c6b0dad80e25..945bc35744ba 100644
|
||||||
|
--- a/proccontrol/src/process.C
|
||||||
|
+++ b/proccontrol/src/process.C
|
||||||
|
@@ -257,41 +257,16 @@ bool int_process::attachThreads()
|
||||||
|
return attachThreads(found_new_threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
-// Attach any new threads and synchronize, until there are no new threads
|
||||||
|
-bool int_process::attachThreadsSync()
|
||||||
|
+bool int_process::plat_attachThreadsSync()
|
||||||
|
{
|
||||||
|
- while (true) {
|
||||||
|
- bool found_new_threads = false;
|
||||||
|
-
|
||||||
|
- ProcPool()->condvar()->lock();
|
||||||
|
- bool result = attachThreads(found_new_threads);
|
||||||
|
- if (found_new_threads)
|
||||||
|
- ProcPool()->condvar()->broadcast();
|
||||||
|
- ProcPool()->condvar()->unlock();
|
||||||
|
-
|
||||||
|
- if (!result) {
|
||||||
|
- pthrd_printf("Failed to attach to threads in %d\n", pid);
|
||||||
|
- setLastError(err_internal, "Could not get threads during attach\n");
|
||||||
|
- return false;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (!found_new_threads)
|
||||||
|
- return true;
|
||||||
|
-
|
||||||
|
- pthrd_printf("Wait again for attach from process %d\n", pid);
|
||||||
|
- bool proc_exited = false;
|
||||||
|
- result = waitAndHandleForProc(true, this, proc_exited);
|
||||||
|
- if (!result) {
|
||||||
|
- perr_printf("Internal error calling waitAndHandleForProc on %d\n", getPid());
|
||||||
|
- setLastError(err_internal, "Error while calling waitAndHandleForProc for attached threads\n");
|
||||||
|
- return false;
|
||||||
|
- }
|
||||||
|
- if (proc_exited) {
|
||||||
|
- perr_printf("Process exited while waiting for user thread stop, erroring\n");
|
||||||
|
- setLastError(err_exited, "Process exited while thread being stopped.\n");
|
||||||
|
- return false;
|
||||||
|
- }
|
||||||
|
+ // By default, platforms just call the idempotent attachThreads().
|
||||||
|
+ // Some platforms may override, e.g. Linux should sync with all threads.
|
||||||
|
+ if (!attachThreads()) {
|
||||||
|
+ pthrd_printf("Failed to attach to threads in %d\n", pid);
|
||||||
|
+ setLastError(err_internal, "Could not get threads during attach\n");
|
||||||
|
+ return false;
|
||||||
|
}
|
||||||
|
+ return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool int_process::attach(int_processSet *ps, bool reattach)
|
||||||
|
@@ -488,7 +463,7 @@ bool int_process::attach(int_processSet *ps, bool reattach)
|
||||||
|
int_process *proc = *i;
|
||||||
|
if (proc->getState() == errorstate)
|
||||||
|
continue;
|
||||||
|
- bool result = proc->attachThreadsSync();
|
||||||
|
+ bool result = proc->plat_attachThreadsSync();
|
||||||
|
if (!result) {
|
||||||
|
pthrd_printf("Failed to attach to threads in %d--now an error\n", proc->pid);
|
||||||
|
procs.erase(i++);
|
||||||
|
|
||||||
|
commit ce0f92e8a61aeb8ca0fea7bb2d2d6a76d38ec6d2
|
||||||
|
Author: Josh Stone <jistone@redhat.com>
|
||||||
|
Date: Wed Nov 16 13:44:37 2016 -0800
|
||||||
|
|
||||||
|
proccontrol: scrub newly created threads that fail to attach
|
||||||
|
|
||||||
|
If `int_thread::createThread` failed to actually attach to the thread,
|
||||||
|
it was leaving the thread object in the process in the `neonatal` state.
|
||||||
|
This failed assertions later when trying to stop all of the process's
|
||||||
|
threads, as it would have handler `stopped` and generator `neonatal`.
|
||||||
|
|
||||||
|
Now when a thread attach fails, it is set to `errorstate` and removed
|
||||||
|
from the active thread pools. The assumption is that this thread simply
|
||||||
|
exited before we could attach, but we can't be sure of that without
|
||||||
|
having access to the ptrace return code (`ESRCH`).
|
||||||
|
|
||||||
|
diff --git a/proccontrol/src/process.C b/proccontrol/src/process.C
|
||||||
|
index 945bc35744ba..66397f5ad93d 100644
|
||||||
|
--- a/proccontrol/src/process.C
|
||||||
|
+++ b/proccontrol/src/process.C
|
||||||
|
@@ -3495,8 +3495,14 @@ int_thread *int_thread::createThread(int_process *proc,
|
||||||
|
bool result = newthr->attach();
|
||||||
|
if (!result) {
|
||||||
|
pthrd_printf("Failed to attach to new thread %d/%d\n", proc->getPid(), lwp_id);
|
||||||
|
+ newthr->getUserState().setState(errorstate);
|
||||||
|
+ newthr->getHandlerState().setState(errorstate);
|
||||||
|
+ newthr->getGeneratorState().setState(errorstate);
|
||||||
|
+ ProcPool()->rmThread(newthr);
|
||||||
|
+ proc->threadPool()->rmThread(newthr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
if (newthr->isUser() && newthr->getUserState().getState() == neonatal) {
|
||||||
|
newthr->getUserState().setState(neonatal_intermediate);
|
||||||
|
newthr->getHandlerState().setState(neonatal_intermediate);
|
||||||
|
|
||||||
|
commit dae2e3d9856c9245e37e1fc3d81ab59be67f932b
|
||||||
|
Author: Josh Stone <jistone@redhat.com>
|
||||||
|
Date: Fri Nov 18 14:49:41 2016 -0800
|
||||||
|
|
||||||
|
proccontrol: fix double-increment while erasing a dead process
|
||||||
|
|
||||||
|
In the attach loop over waitfor_startup(), processes which fail are
|
||||||
|
erased from the set. However, the iterator was getting incremented
|
||||||
|
again, which will skip the next process or even cause undefined behavior
|
||||||
|
if already at the end of the list.
|
||||||
|
|
||||||
|
With GCC 6.2.1, that UB manifested as an infinite loop on a self-
|
||||||
|
referential rbtree node.
|
||||||
|
|
||||||
|
The simple solution is to `continue` the loop after `erase(i++)`, as is
|
||||||
|
done in many other places with this same pattern.
|
||||||
|
|
||||||
|
diff --git a/proccontrol/src/process.C b/proccontrol/src/process.C
|
||||||
|
index 66397f5ad93d..32bfc8fb2a5c 100644
|
||||||
|
--- a/proccontrol/src/process.C
|
||||||
|
+++ b/proccontrol/src/process.C
|
||||||
|
@@ -453,6 +453,7 @@ bool int_process::attach(int_processSet *ps, bool reattach)
|
||||||
|
pthrd_printf("Error waiting for attach to %d\n", proc->pid);
|
||||||
|
procs.erase(i++);
|
||||||
|
had_error = true;
|
||||||
|
+ continue;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
commit cb81d5342d9b99143312186ef558e49bcb37cd65
|
||||||
|
Author: Josh Stone <jistone@redhat.com>
|
||||||
|
Date: Mon Nov 21 11:52:48 2016 -0800
|
||||||
|
|
||||||
|
proccontrol: fix another process erasure during attach
|
||||||
|
|
||||||
|
If a process initially failed to attach threads, a `pthrd_printf` was
|
||||||
|
indicating that it would try again, but the process was getting erased
|
||||||
|
from the set while incorrectly causing the iterator to double-increment.
|
||||||
|
|
||||||
|
Now the messages about "will try again" and "now an error" are changed
|
||||||
|
to simply report an immediate error, and it continus the loop after
|
||||||
|
process erasure to avoid incrementing the iterator again.
|
||||||
|
|
||||||
|
diff --git a/proccontrol/src/process.C b/proccontrol/src/process.C
|
||||||
|
index 32bfc8fb2a5c..548f6908f9d1 100644
|
||||||
|
--- a/proccontrol/src/process.C
|
||||||
|
+++ b/proccontrol/src/process.C
|
||||||
|
@@ -381,8 +381,10 @@ bool int_process::attach(int_processSet *ps, bool reattach)
|
||||||
|
pthrd_printf("Attaching to threads for %d\n", proc->getPid());
|
||||||
|
bool result = proc->attachThreads();
|
||||||
|
if (!result) {
|
||||||
|
- pthrd_printf("Could not attach to threads in %d--will try again\n", proc->pid);
|
||||||
|
+ pthrd_printf("Failed to attach to threads in %d\n", proc->pid);
|
||||||
|
procs.erase(i++);
|
||||||
|
+ had_error = true;
|
||||||
|
+ continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reattach) {
|
||||||
|
@@ -466,7 +468,7 @@ bool int_process::attach(int_processSet *ps, bool reattach)
|
||||||
|
continue;
|
||||||
|
bool result = proc->plat_attachThreadsSync();
|
||||||
|
if (!result) {
|
||||||
|
- pthrd_printf("Failed to attach to threads in %d--now an error\n", proc->pid);
|
||||||
|
+ pthrd_printf("Failed to attach to threads in %d\n", proc->pid);
|
||||||
|
procs.erase(i++);
|
||||||
|
had_error = true;
|
||||||
|
continue;
|
@ -2,7 +2,7 @@ Summary: An API for Run-time Code Generation
|
|||||||
License: LGPLv2+
|
License: LGPLv2+
|
||||||
Name: dyninst
|
Name: dyninst
|
||||||
Group: Development/Libraries
|
Group: Development/Libraries
|
||||||
Release: 4%{?dist}
|
Release: 5%{?dist}
|
||||||
URL: http://www.dyninst.org
|
URL: http://www.dyninst.org
|
||||||
Version: 9.2.0
|
Version: 9.2.0
|
||||||
# Dyninst only has full support for a few architectures.
|
# Dyninst only has full support for a few architectures.
|
||||||
@ -14,6 +14,7 @@ Source0: https://github.com/dyninst/dyninst/archive/v9.2.0.tar.gz#/%{name}-%{ver
|
|||||||
Source1: https://github.com/dyninst/dyninst/releases/download/v9.2.0/Testsuite-9.2.0.zip
|
Source1: https://github.com/dyninst/dyninst/releases/download/v9.2.0/Testsuite-9.2.0.zip
|
||||||
|
|
||||||
Patch1: dyninst-9.2.0-proccontrol-attach-no-exe.patch
|
Patch1: dyninst-9.2.0-proccontrol-attach-no-exe.patch
|
||||||
|
Patch2: dyninst-9.2.0-proccontrol-thread-races.patch
|
||||||
|
|
||||||
%global dyninst_base dyninst-%{version}
|
%global dyninst_base dyninst-%{version}
|
||||||
%global testsuite_base testsuite-master
|
%global testsuite_base testsuite-master
|
||||||
@ -86,6 +87,7 @@ making sure that dyninst works properly.
|
|||||||
%setup -q -T -D -a 1
|
%setup -q -T -D -a 1
|
||||||
|
|
||||||
%patch1 -p1 -d %{dyninst_base} -b .attach-no-exe
|
%patch1 -p1 -d %{dyninst_base} -b .attach-no-exe
|
||||||
|
%patch2 -p1 -d %{dyninst_base} -b .attach-thread-races
|
||||||
|
|
||||||
%build
|
%build
|
||||||
|
|
||||||
@ -175,6 +177,9 @@ find %{buildroot}%{_libdir}/dyninst/testsuite/ \
|
|||||||
%attr(644,root,root) %{_libdir}/dyninst/testsuite/*.a
|
%attr(644,root,root) %{_libdir}/dyninst/testsuite/*.a
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Nov 22 2016 Josh Stone <jistone@redhat.com> - 9.2.0-5
|
||||||
|
- Backport fixes for rhbz1373197, attach thread races.
|
||||||
|
|
||||||
* Wed Sep 14 2016 Josh Stone <jistone@redhat.com> - 9.2.0-4
|
* Wed Sep 14 2016 Josh Stone <jistone@redhat.com> - 9.2.0-4
|
||||||
- Fix rhbz1373239, process attach without exe specified.
|
- Fix rhbz1373239, process attach without exe specified.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user