develooper Front page | perl.perl5.porters | Postings from August 2012

[perl #33096] win32_msgwait runs forever with non-infinite timeout

Thread Previous | Thread Next
bulk 88 via RT
August 20, 2012 23:21
[perl #33096] win32_msgwait runs forever with non-infinite timeout
Message ID:
On Fri Dec 17 19:11:29 2004, cbecker wrote:
> This is a bug report for perl from,
> generated with the help of perlbug 1.35 running under perl v5.8.5.
> -----------------------------------------------------------------
> win32_msgwait will loop forever under the condition that none of the
> becomes ready, while MsgWaitForMultipleObjects keeps on returning events
> before the timeout (non-infinite) is ever hit.
> Just ran into this (timeout: 1 second) and had a debugger handy -
looking at
> the source, this should be fairly easy to understand & recreate. The
> solution would be to decrease the timeout by the amount waited with every
> run - watch out for DWORD overflows!
Looking at
. There is a wall time check and the timer is decreased (actually
increased towards expire time) correctly but there is a race with a
deadlock (near infinity timeout) if the delay from
MsgWaitForMultipleObjects to GetTickCount exceeds 1 ms causing var ticks
to go > var timeout. For "while MsgWaitForMultipleObjects keeps on
returning events before the timeout (non-infinite) is ever hit", if the
Perl process is getting a denial-of-service attack through the Windows
Message queue from a a different abusive process, there is nothing Perl
can do about it. The PC will be 100% cpu usage anyway from the abusive
process. If the messages won't be processed in win32_msgwait they will
be processed anyway in assorted perl opcodes in PERL_ASYNC_CHECK()s.

I was able to create a deadlock with a C debugger by doing a Perl "sleep
3;" and creating the delay with breakpoints with a C debugger. Windows
running in VM or with a very badly coded driver could cause a context
switch that would cause the >= 1 ms delay.

I have a patch nearly complete to prevent the race condition above, but
I realized a different race condition, the 49.7 day overflow, see
. The only bug the 49.7 day overflow I see creating is, if you sleep for
more than 50 days, sleep() will return ~ < 1 day of sleep seconds
instead of > 49 days of sleep seconds. So I have 4 choices.

1. Keep GetTickCount and put the 49.7 days of sleep actual seconds slept
bug in perlwin32/BUGS AND CAVEATS section as a wont fix. Microsoft
considers a likely enough scenario they test apps for the bug, see and search
the page for GetTickCount.

2. Replace GetTickCount with QueryPerformanceCounter
. The difficulty with this is, in what psuedo global or real global
struct do I keep the frequency (
) in? It needs to be stored once per Perl DLL loading (non static
build), or once per perl process startup (static build, no perl library
dll), not queried on every ithread interp creation and stored in a
my_perl member (duplicate calls to QueryPerformanceFrequency, I am
probably microoptimizing here). Is there a way of storing truly process
global (not interp global) data that doesn't have a const initializer or
just put it in struct interp_intern and refetch it with
QueryPerformanceFrequency as needed, the more efficient way is simply
too difficult with perl's architecture?

3. Replace GetTickCount with GetSystemTimeAsFileTime
. I dont know what GetSystemTimeAsFileTime's leap second behavior is.

4. If sleep delta > (49.7 days to seconds/2) assume we overflowed and
panic/croak. This doesn't seem like a good idea.

The Perl community's input is needed and appreciated.

via perlbug:  queue: perl5 status: new

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About