Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

potential race condition when mixing signals and select() #11458

Closed
p5pRT opened this issue Jun 23, 2011 · 24 comments
Closed

potential race condition when mixing signals and select() #11458

p5pRT opened this issue Jun 23, 2011 · 24 comments

Comments

@p5pRT
Copy link

p5pRT commented Jun 23, 2011

Migrated from rt.perl.org#93428 (status was 'open')

Searchable as RT93428$

@p5pRT
Copy link
Author

p5pRT commented Jun 23, 2011

From pc88mxer@gmail.com

From this discussion on perlmonks​:

http​://perlmonks.com/?node_id=908535

it seems there is a race condition when mixing signals and select().

A solution is to use pselect() instead of select() when available.

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.12.1:

Configured by pc88mxer at Wed Aug  4 11:52:39 CDT 2010.

Summary of my perl5 (revision 5 version 12 subversion 1) configuration:

  Platform:
    osname=linux, osvers=2.6.32-24-generic-pae, archname=i686-linux
    uname='linux pc88mxer-laptop 2.6.32-24-generic-pae #38-ubuntu smp
mon jul 5 10:54:21 utc 2010 i686 gnulinux '
    config_args='-des -Dprefix=/home/pc88mxer/apps/perl-5.12'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=undef, use64bitall=undef, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-fno-strict-aliasing -pipe -fstack-protector
-I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2',
    cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.4.3', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib /usr/lib64
    libs=-lnsl -ldl -lm -lcrypt -lutil -lc
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
    libc=/lib/libc-2.11.1.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.11.1'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib
-fstack-protector'

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

From @Leont

On Thu Jun 23 12​:27​:39 2011, pc88mxer@​gmail.com wrote​:

[Please describe your issue here]

From this discussion on perlmonks​:

http​://perlmonks.com/?node_id=908535

it seems there is a race condition when mixing signals and select().

A solution is to use pselect() instead of select() when available.

This is *not* a perl bug. but a fundamental difficulty in dealing with
signals. I suggest closing this ticket.

Leon

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

@cpansprout - Status changed from 'open' to 'rejected'

@p5pRT p5pRT closed this as completed Dec 11, 2011
@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

From @ikegami

On Sun, Dec 11, 2011 at 2​:55 PM, Leon Timmermans via RT <
perlbug-followup@​perl.org> wrote​:

On Thu Jun 23 12​:27​:39 2011, pc88mxer@​gmail.com wrote​:

[Please describe your issue here]

From this discussion on perlmonks​:

http​://perlmonks.com/?node_id=908535

it seems there is a race condition when mixing signals and select().

A solution is to use pselect() instead of select() when available.

This is *not* a perl bug. but a fundamental difficulty in dealing with
signals. I suggest closing this ticket.

It's not "fundamentally difficult". It's been solved
Perl using a buggy method of handling signals

Leon

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

From @ikegami

Disregard the previous message from me. It was sent accidentally far before
it was ready to be sent.

On Sun, Dec 11, 2011 at 5​:03 PM, Eric Brine <ikegami@​adaelis.com> wrote​:

On Sun, Dec 11, 2011 at 2​:55 PM, Leon Timmermans via RT <
perlbug-followup@​perl.org> wrote​:

On Thu Jun 23 12​:27​:39 2011, pc88mxer@​gmail.com wrote​:

[Please describe your issue here]

From this discussion on perlmonks​:

http​://perlmonks.com/?node_id=908535

it seems there is a race condition when mixing signals and select().

A solution is to use pselect() instead of select() when available.

This is *not* a perl bug. but a fundamental difficulty in dealing with
signals. I suggest closing this ticket.

It's not "fundamentally difficult". It's been solved
Perl using a buggy method of handling signals

Leon

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

From @cpansprout

On Sun Dec 11 14​:05​:26 2011, ikegami@​adaelis.com wrote​:

Disregard the previous message from me. It was sent accidentally far
before
it was ready to be sent.

Forgive me, but I find it quite funny. :-) It sounds like something I
wrote.

On Sun, Dec 11, 2011 at 5​:03 PM, Eric Brine <ikegami@​adaelis.com> wrote​:

On Sun, Dec 11, 2011 at 2​:55 PM, Leon Timmermans via RT <
perlbug-followup@​perl.org> wrote​:

On Thu Jun 23 12​:27​:39 2011, pc88mxer@​gmail.com wrote​:

[Please describe your issue here]

From this discussion on perlmonks​:

http​://perlmonks.com/?node_id=908535

it seems there is a race condition when mixing signals and select().

A solution is to use pselect() instead of select() when available.

This is *not* a perl bug. but a fundamental difficulty in dealing with
signals. I suggest closing this ticket.

It's not "fundamentally difficult". It's been solved
Perl using a buggy method of handling signals

Leon

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

From @ikegami

On Sun, Dec 11, 2011 at 2​:55 PM, Leon Timmermans via RT <
perlbug-followup@​perl.org> wrote​:

On Thu Jun 23 12​:27​:39 2011, pc88mxer@​gmail.com wrote​:

[Please describe your issue here]

From this discussion on perlmonks​:

http​://perlmonks.com/?node_id=908535

it seems there is a race condition when mixing signals and select().

A solution is to use pselect() instead of select() when available.

This is *not* a perl bug. but a fundamental difficulty in dealing with
signals. I suggest closing this ticket.

Perl signal handling uses an approach that suffers from a race condition.
It's buggy.

As for being a "fundamentally difficulty", just because race conditons can
be tricky to avoid when using threads or signals doesn't mean we shouldn't
fix them. And it's neither tricky nor difficult to solve on systems with
pselect.

- Eric

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

@cpansprout - Status changed from 'rejected' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Dec 12, 2011

From @Leont

On Sun, Dec 11, 2011 at 11​:11 PM, Eric Brine <ikegami@​adaelis.com> wrote​:

Perl signal handling uses an approach that suffers from a race condition.
It's buggy.

That's no news. Are you suggestion a solution?

As for being a "fundamentally difficulty", just because race conditons can
be tricky to avoid when using threads or signals doesn't mean we shouldn't
fix them.

Life is much easier when you know exactly what the user wants, but
core can't make any assumptions, that is the problem. Core doesn't
know which signal should be blocked when, only the user does. There is
no magical solution, best we can do is doing exactly what the user
asks us to do, and assume he knows what he's doing.

And it's neither tricky nor difficult to solve on systems with
pselect.

Even if it was portable, it's not going to solve the problem by itself.

Leon

@p5pRT
Copy link
Author

p5pRT commented Dec 12, 2011

From @Leont

On Mon, Dec 12, 2011 at 4​:03 AM, Leon Timmermans <fawaka@​gmail.com> wrote​:

Even if it was portable, it's not going to solve the problem by itself.

Thinking about it a little more, I think we can prevent the race
condition between PERL_ASYNC_CHECK and select(2) with sigprocmask +
pselect, if that's what you mean. I suspect that still leaves open
plenty of other issues though.

Leon

@p5pRT
Copy link
Author

p5pRT commented Jan 12, 2012

From pc88mxer@gmail.com

On Sun, Dec 11, 2011 at 1​:55 PM, Leon Timmermans via RT
<perlbug-followup@​perl.org> wrote​:

On Thu Jun 23 12​:27​:39 2011, pc88mxer@​gmail.com wrote​:

[Please describe your issue here]

From this discussion on perlmonks​:

http​://perlmonks.com/?node_id=908535

it seems there is a race condition when mixing signals and select().

A solution is to use pselect() instead of select() when available.

This is *not* a perl bug. but a fundamental difficulty in dealing with
signals. I suggest closing this ticket.

I think the suggestion is that perl should use pselect(2) instead of
select(2) when available.

Alternatively perl could add support for pselect and keep the current
behaviour of the select().

Comments?

@p5pRT
Copy link
Author

p5pRT commented Jan 12, 2012

From @Leont

On Wed, Jan 11, 2012 at 11​:22 PM, E R <pc88mxer@​gmail.com> wrote​:

I think the suggestion is that perl should use pselect(2) instead of
select(2) when available.

Alternatively perl could add support for pselect and keep the current
behaviour of the select().

Comments?

This bug report suffers from the problem that it doesn't describe *at
all* what the really bug is, just that this class of bugs exists, nor
what exactly the solution would be​: it certainly wouldn't be
s/select/pselect/.

What I suspect they mean here is that there is a race condition
between the deferred signal table and select. If a signal arrives
after the last PERL_ASYNC_CHECK but before select(2), it will be
handled *after* the select call; this would break for example the
self-pipe trick (ironically). A sigprocmask, PERL_ASYNC_CHECK,
pselect, sigprocmask sequence could alleviate that.

This does leave open the possibility of users making the same mistake
in their own code though, which I suspect is not uncommon.

Leon

@p5pRT
Copy link
Author

p5pRT commented Jan 12, 2012

From @leonerd

On Sun, Dec 11, 2011 at 11​:55​:40AM -0800, Leon Timmermans via RT wrote​:

it seems there is a race condition when mixing signals and select().

A solution is to use pselect() instead of select() when available.

This is *not* a perl bug. but a fundamental difficulty in dealing with
signals. I suggest closing this ticket.

I agree. It's a well-known limitation in the API design of select(2).

pselect(2) and ppoll(2) work around it. E.g. note my own IO​::Ppoll, an
IO​::Poll-compatible dropin replacement that uses ppoll(2).

--
Paul "LeoNerd" Evans

leonerd@​leonerd.org.uk
ICQ# 4135350 | Registered Linux# 179460
http​://www.leonerd.org.uk/

@p5pRT
Copy link
Author

p5pRT commented Jan 13, 2012

From @nwc10

On Thu, Jan 12, 2012 at 05​:11​:50PM +0100, Leon Timmermans wrote​:

On Wed, Jan 11, 2012 at 11​:22 PM, E R <pc88mxer@​gmail.com> wrote​:

I think the suggestion is that perl should use pselect(2) instead of
select(2) when available.

Alternatively perl could add support for pselect and keep the current
behaviour of the select().

Comments?

This bug report suffers from the problem that it doesn't describe *at
all* what the really bug is, just that this class of bugs exists, nor
what exactly the solution would be​: it certainly wouldn't be
s/select/pselect/.

Agree.

What I suspect they mean here is that there is a race condition
between the deferred signal table and select. If a signal arrives
after the last PERL_ASYNC_CHECK but before select(2), it will be
handled *after* the select call; this would break for example the
self-pipe trick (ironically). A sigprocmask, PERL_ASYNC_CHECK,
pselect, sigprocmask sequence could alleviate that.

As in
  remember the current signal state
  sigprocmask to block all signals
  PERL_ASYNC_CHECK to flush all pending safe signals
  pselect, restoring the "current" signal state
  (to ensure that it can be interrupted correctly)
  sigprocmask to restore the "current" state

?

I think that would "not be inconsistent" with the current expected behaviour
of select. "All" it does is ensure signals are processed in a more timely
fashion, but in a way that is actually very helpful.

I think it would be worth doing.

This does leave open the possibility of users making the same mistake
in their own code though, which I suspect is not uncommon.

If the mistake (we're guessing at, given the vague nature of the "bug"
report) is to lose signals just before calling select, then I can't see
how one is going to avoid it *at Perl level* if one only has select(),
given how "safe" signals work - ie they don't execute the Perl code within
the signal handler.

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented Jan 13, 2012

From @Leont

On Fri, Jan 13, 2012 at 12​:19 PM, Nicholas Clark <nick@​ccl4.org> wrote​:

As in
   remember the current signal state
   sigprocmask to block all signals
   PERL_ASYNC_CHECK to flush all pending safe signals
   pselect, restoring the "current" signal state
       (to ensure that it can be interrupted correctly)
   sigprocmask to restore the "current" state

?

Yes, though step 1 & 2 are really one atomic step, and some signals
are better not blocked (e.g. SEGV, BUS, ILL; they aren't deferred
anyway). Also, judging by the documentation many implementations (OS
X, FreeBSD <= 8.0, possibly others) pselect is a non-atomic wrapper
around select+sigprocmask, making it fairly useless.

I think that would "not be inconsistent" with the current expected behaviour
of select. "All" it does is ensure signals are processed in a more timely
fashion, but in a way that is actually very helpful.

I think it would be worth doing.

Me too, though it would stop select from returning a meaningful
$time_left on platforms that do that (Linux).

If the mistake (we're guessing at, given the vague nature of the "bug"
report) is to lose signals just before calling select, then I can't see
how one is going to avoid it *at Perl level* if one only has select(),
given how "safe" signals work - ie they don't execute the Perl code within
the signal handler.

I agree. There are some solutions available CPAN, but the only
portable thing is in a rather broken state.

Leon

@p5pRT
Copy link
Author

p5pRT commented Jan 13, 2012

From @nwc10

On Fri, Jan 13, 2012 at 05​:27​:09PM +0100, Leon Timmermans wrote​:

On Fri, Jan 13, 2012 at 12​:19 PM, Nicholas Clark <nick@​ccl4.org> wrote​:

As in
   remember the current signal state
   sigprocmask to block all signals
   PERL_ASYNC_CHECK to flush all pending safe signals
   pselect, restoring the "current" signal state
       (to ensure that it can be interrupted correctly)
   sigprocmask to restore the "current" state

?

Yes, though step 1 & 2 are really one atomic step, and some signals
are better not blocked (e.g. SEGV, BUS, ILL; they aren't deferred
anyway). Also, judging by the documentation many implementations (OS
X, FreeBSD <= 8.0, possibly others) pselect is a non-atomic wrapper
around select+sigprocmask, making it fairly useless.

Gah, and I suspect it's really hard, if not impossible, to probe for that.
hints files?

I think that would "not be inconsistent" with the current expected behaviour
of select. "All" it does is ensure signals are processed in a more timely
fashion, but in a way that is actually very helpful.

I think it would be worth doing.

Me too, though it would stop select from returning a meaningful
$time_left on platforms that do that (Linux).

Bother. No plan survives contact with the enemy.

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented Jan 15, 2012

From @ikegami

On Fri, Jan 13, 2012 at 11​:38 AM, Nicholas Clark <nick@​ccl4.org> wrote​:

On Fri, Jan 13, 2012 at 05​:27​:09PM +0100, Leon Timmermans wrote​:

Me too, though it would stop select from returning a meaningful

$time_left on platforms that do that (Linux).

Bother. No plan survives contact with the enemy.

Really? Sounds like that could easily be emulated (when called in listay
context), or is there some difficulty in doing that?

- Eric

@p5pRT
Copy link
Author

p5pRT commented Jan 18, 2012

From @Leont

On Sun, Jan 15, 2012 at 8​:28 AM, Eric Brine <ikegami@​adaelis.com> wrote​:

Really? Sounds like that could easily be emulated (when called in listay
context), or is there some difficulty in doing that?

It can, but I'm not sure if it's really all that meaningful anymore
(users might as well do it themselves that way). Also, if we do this
(I'm not quite convinced we should) shouldn't we do the same on other
platforms as well?

Leon

@p5pRT
Copy link
Author

p5pRT commented Jan 18, 2012

From @nwc10

On Wed, Jan 18, 2012 at 01​:58​:48AM +0100, Leon Timmermans wrote​:

On Sun, Jan 15, 2012 at 8​:28 AM, Eric Brine <ikegami@​adaelis.com> wrote​:

Really? Sounds like that could easily be emulated (when called in listay
context), or is there some difficulty in doing that?

It can, but I'm not sure if it's really all that meaningful anymore
(users might as well do it themselves that way). Also, if we do this
(I'm not quite convinced we should) shouldn't we do the same on other
platforms as well?

I'm not sure either.

But I don't think that it would be *that* expensive in the general case, as
we'd only need to do the work when select is in list context.
Also, we could decide that we're only going to do emulation if both
(a real) pselect and gettimeofday are present, to simplify the code.

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented May 27, 2012

From @Leont

On Fri Jan 13 08​:39​:09 2012, nicholas wrote​:

Gah, and I suspect it's really hard, if not impossible, to probe for
that.
hints files?

To the contrary, it seems quite easy. Set a signal-handler (without the
SA_RESTART flag), block that signal, send it to the process and then do
a pselect unblocking that signal. If it's a real pselect, it will be
interrupted and thus return EINTR. If pselect is faked the signal will
arrive right after the sigprocmask (and thus before the select) so it
won't be interrupted.

Leon

@p5pRT
Copy link
Author

p5pRT commented May 27, 2012

From @Leont

On Wed Jan 18 06​:55​:25 2012, nicholas wrote​:

I'm not sure either.

But I don't think that it would be *that* expensive in the general
case, as
we'd only need to do the work when select is in list context.
Also, we could decide that we're only going to do emulation if both
(a real) pselect and gettimeofday are present, to simplify the code.

Problem is, $time_left is *before* running signal handlers, while we can
only measure it *after*. Any emulation would have a hole, that can
actually be bigger than $timeout.

Leon

@p5pRT
Copy link
Author

p5pRT commented Jun 1, 2012

From @nwc10

On Sun, May 27, 2012 at 03​:34​:02PM -0700, Leon Timmermans via RT wrote​:

On Fri Jan 13 08​:39​:09 2012, nicholas wrote​:

Gah, and I suspect it's really hard, if not impossible, to probe for
that.
hints files?

To the contrary, it seems quite easy. Set a signal-handler (without the
SA_RESTART flag), block that signal, send it to the process and then do
a pselect unblocking that signal. If it's a real pselect, it will be
interrupted and thus return EINTR. If pselect is faked the signal will
arrive right after the sigprocmask (and thus before the select) so it
won't be interrupted.

Nice trick. Who is writing the demo code? :-)

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented Jun 5, 2012

From @Leont

On Fri, Jun 1, 2012 at 12​:00 PM, Nicholas Clark <nick@​ccl4.org> wrote​:

On Sun, May 27, 2012 at 03​:34​:02PM -0700, Leon Timmermans via RT wrote​:

On Fri Jan 13 08​:39​:09 2012, nicholas wrote​:

Gah, and I suspect it's really hard, if not impossible, to probe for
that.
hints files?

To the contrary, it seems quite easy. Set a signal-handler (without the
SA_RESTART flag), block that signal, send it to the process and then do
a pselect unblocking that signal. If it's a real pselect, it will be
interrupted and thus return EINTR. If pselect is faked the signal will
arrive right after the sigprocmask (and thus before the select) so it
won't be interrupted.

Nice trick. Who is writing the demo code? :-)

The trick is from POSIX​::pselect's test suite and it seems to be
correct on all major platform :-)

Leon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant