diff -r 403565c0e5de Modules/overlapped.c --- a/Modules/overlapped.c Tue Jan 28 02:24:22 2014 +0100 +++ b/Modules/overlapped.c Tue Jan 28 09:45:33 2014 +0100 @@ -536,7 +536,7 @@ static void Overlapped_dealloc(OverlappedObject *self) { DWORD bytes; - DWORD olderr = GetLastError(); + DWORD err, olderr = GetLastError(); BOOL wait = FALSE; BOOL ret; @@ -551,17 +551,31 @@ Overlapped_dealloc(OverlappedObject *sel &bytes, wait); Py_END_ALLOW_THREADS - switch (ret ? ERROR_SUCCESS : GetLastError()) { + err = ret ? ERROR_SUCCESS : GetLastError(); + switch (err) { case ERROR_SUCCESS: case ERROR_NOT_FOUND: case ERROR_OPERATION_ABORTED: break; default: - PyErr_Format( - PyExc_RuntimeError, - "%R still has pending operation at " - "deallocation, the process may crash", self); - PyErr_WriteUnraisable(NULL); + if (Py_Finalizing == NULL) { + PyErr_Format( + PyExc_RuntimeError, + "%R still has pending operation at " + "deallocation, the process may crash", self); + PyErr_WriteUnraisable(NULL); + } + else { + /* The operation is still pending, but the process is + probably about to exit, so we need not worry too much + about memory leaks. Leaking self prevents a potential + crash. This can happen when a daemon thread is cleaned + up at exit -- see #19565. We only expect to get here + on Windows XP. */ + CloseHandle(self->overlapped.hEvent); + SetLastError(err); + return; + } } }