This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
win32.c: rework the waitpid(-1, WNOHANG) fix
authorTomasz Konojacki <me@xenu.pl>
Wed, 18 Mar 2020 02:17:52 +0000 (03:17 +0100)
committerKarl Williamson <khw@cpan.org>
Fri, 24 Jul 2020 18:25:04 +0000 (12:25 -0600)
Oops! While 08e55ec5e3ef6d6c040c0dc8bdec7d59f76bfbe8 made
waitpid(-1, WNOHANG) not segfault, it introduced another problem:
when retry == 1, MsgWaitForMultipleObjects() will sometimes be
called with a very large timeout due to unsigned integer overflow.

This is *exactly* the same problem that the comment above the loop
warns about.

win32/win32.c

index e3769b5..9719f14 100644 (file)
@@ -2239,7 +2239,6 @@ win32_async_check(pTHX)
 DllExport DWORD
 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
 {
-    int retry = 0;
     /* We may need several goes at this - so compute when we stop */
     FT_t ticks = {0};
     unsigned __int64 endtime = timeout;
@@ -2262,13 +2261,12 @@ win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD result
      * from another process (msctf.dll doing IPC among its instances, VS debugger
      * causes msctf.dll to be loaded into Perl by kernel), see [perl #33096].
      */
-    while (ticks.ft_i64 <= endtime || retry) {
+    while (ticks.ft_i64 <= endtime) {
        /* if timeout's type is lengthened, remember to split 64b timeout
         * into multiple non-infinity runs of MWFMO */
        DWORD result = MsgWaitForMultipleObjects(count, handles, FALSE,
                                                (DWORD)(endtime - ticks.ft_i64),
                                                QS_POSTMESSAGE|QS_TIMER|QS_SENDMESSAGE);
-        retry = 0;
        if (resultp)
           *resultp = result;
        if (result == WAIT_TIMEOUT) {
@@ -2284,7 +2282,12 @@ win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD result
        if (result == WAIT_OBJECT_0 + count) {
            /* Message has arrived - check it */
            (void)win32_async_check(aTHX);
-            retry = 1;
+
+            /* retry */
+            if (ticks.ft_i64 > endtime)
+                endtime = ticks.ft_i64;
+
+            continue;
        }
        else {
           /* Not timeout or message - one of handles is ready */