proc/native: race between RequestManualStop and trapWait

RequestManualStop will run concurrently with trapWait, since one writes
dbp.halt and the other reads it dbp.halt should be protected by a
mutex.

Updates #830
This commit is contained in:
aarzilli 2017-06-06 16:49:52 +02:00 committed by Alessandro Arzilli
parent 640dedb479
commit 98142c695b
3 changed files with 15 additions and 3 deletions

@ -37,6 +37,7 @@ type Process struct {
breakpointIDCounter int breakpointIDCounter int
internalBreakpointIDCounter int internalBreakpointIDCounter int
firstStart bool firstStart bool
haltMu sync.Mutex
halt bool halt bool
exited bool exited bool
ptraceChan chan func() ptraceChan chan func()
@ -187,6 +188,8 @@ func (dbp *Process) RequestManualStop() error {
if dbp.exited { if dbp.exited {
return &proc.ProcessExitedError{} return &proc.ProcessExitedError{}
} }
dbp.haltMu.Lock()
defer dbp.haltMu.Unlock()
dbp.halt = true dbp.halt = true
return dbp.requestManualStop() return dbp.requestManualStop()
} }

@ -291,7 +291,10 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
return nil, proc.ProcessExitedError{Pid: dbp.pid, Status: status.ExitStatus()} return nil, proc.ProcessExitedError{Pid: dbp.pid, Status: status.ExitStatus()}
case C.MACH_RCV_INTERRUPTED: case C.MACH_RCV_INTERRUPTED:
if !dbp.halt { dbp.haltMu.Lock()
halt := dbp.halt
dbp.haltMu.Unlock()
if !halt {
// Call trapWait again, it seems // Call trapWait again, it seems
// MACH_RCV_INTERRUPTED is emitted before // MACH_RCV_INTERRUPTED is emitted before
// process natural death _sometimes_. // process natural death _sometimes_.
@ -319,7 +322,10 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
dbp.updateThreadList() dbp.updateThreadList()
th, ok := dbp.threads[int(port)] th, ok := dbp.threads[int(port)]
if !ok { if !ok {
if dbp.halt { dbp.haltMu.Lock()
halt := dbp.halt
dbp.haltMu.Unlock()
if halt {
dbp.halt = false dbp.halt = false
return th, nil return th, nil
} }

@ -236,7 +236,10 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
// Sometimes we get an unknown thread, ignore it? // Sometimes we get an unknown thread, ignore it?
continue continue
} }
if status.StopSignal() == sys.SIGTRAP && dbp.halt { dbp.haltMu.Lock()
halt := dbp.halt
dbp.haltMu.Unlock()
if status.StopSignal() == sys.SIGTRAP && halt {
th.running = false th.running = false
dbp.halt = false dbp.halt = false
return th, nil return th, nil