1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

testcrypt.py: avoid restarting subprocess for frees.

I just ran into a bug in which the testcrypt child process was cleanly
terminated, but at least one Python object was left lying around
containing the identifier of a testcrypt object that had never been
freed. On program exit, the Python reference count on that object went
to zero, the __del__ method was invoked, and childprocess.funcall
started a _new_ instance of testcrypt just so it could tell it to free
the object identifier - which, of course, the new testcrypt had never
heard of!

We can already tell the difference between a ChildProcess object which
has no subprocess because it hasn't yet been started, and one which
has no subprocess because it's terminated: the latter has exitstatus
set to something other than None. So now we enforce by assertion that
we don't ever restart the child process, and the __del__ method avoids
doing anything if the child has already finished.
This commit is contained in:
Simon Tatham 2020-02-29 10:54:16 +00:00
parent db7a314c38
commit 809a4eb249

View File

@ -69,8 +69,11 @@ class ChildProcess(object):
if self.debug is not None:
self.debug.write("recv: {}\n".format(line))
return line
def already_terminated(self):
return self.sp is None and self.exitstatus is not None
def funcall(self, cmd, args):
if self.sp is None:
assert self.exitstatus is None
self.start()
self.write_line(unicode_to_bytes(cmd) + b" " + b" ".join(
unicode_to_bytes(arg) for arg in args))
@ -117,7 +120,7 @@ class Value(object):
def __repr__(self):
return "Value({!r}, {!r})".format(self._typename, self._ident)
def __del__(self):
if self._ident is not None:
if self._ident is not None and not childprocess.already_terminated():
try:
childprocess.funcall("free", [self._ident])
except ChildProcessFailure: