这是我的(相当冗长的)功能:
def go(self, target, outfile, infile, stderr=sys.stderr, timeout=None):
self.pre_proc_started()
try:
infile_fileno = infile.fileno()
except AttributeError:
infile_fileno = None
p_stdin = infile if infile_fileno is not None else subprocess.PIPE
if timeout is not None:
p = [None]
def kill_process(p):
if p[0]:
p[0].kill()
else:
print("WTH")
timer = threading.Timer(timeout, lambda: kill_process(p))
timer.start()
p[0] = subprocess.Popen(target, stdin=p_stdin, stderr=stderr,
env={'__AFL_SHM_ID': str(self.shm_id)})
try:
if p_stdin == subprocess.PIPE:
p[0].stdin.write(infile.read())
p[0].stdin.close()
except IOError: # brobably broken pipe
raise
p[0].wait()
if timeout is not None:
timer.cancel()
self.post_proc_started()
trace_bytes_addr = shmat(self.shm_id, 0, 0)
if trace_bytes_addr == 2**64 - 1:
raise RuntimeError("shmat() failed (%s)" % os.strerror(errno()))
trace_bytes = ctypes.string_at(ctypes.c_void_p(trace_bytes_addr),
MAP_SIZE)
return trace_bytes
为什么我觉得很难相信,如果我运行足够多次,p[0]
为None
,我就会打印WTH
。那是为什么?
答案 0 :(得分:1)
因为你有竞争条件..你在调用Popen之前启动Timer(带超时)并将p [0]设置为非None值。如果子进程在Timer触发之前没有设置并返回Popen对象,则当您尝试终止进程时,您将看到p [0]为None。
确保您的超时值足够高或等到您在启动计时器之前调用Popen之后。
答案 1 :(得分:1)
运行时:
timer = threading.Timer(timeout, lambda: kill_process(p))
timer.start()
你启动一个新线程。然后,OS可以抢占您当前的线程并运行新线程一段时间(或者在其他进程中在系统上运行的任何其他线程)。如果系统非常繁忙或您非常不走运,那么您的线程可能会被抢占的时间超过timeout
。在您填充p[0]
之前,您不应该启动计时器。