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

strange behaviour when forking lots of times #3882

Open
p5pRT opened this issue Apr 21, 2001 · 8 comments
Open

strange behaviour when forking lots of times #3882

p5pRT opened this issue Apr 21, 2001 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 21, 2001

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

Searchable as RT6847$

@p5pRT
Copy link
Author

p5pRT commented Apr 21, 2001

From dpc29@cam.ac.uk

$ perl -we 'fork || print for split //, "a" x 10'

when I run that on my computer, I get strange output. Instead of
printing "a" 2**10 times, the output contains random "1"'s, like this​:

aa1aaaaa1aaa1aaaaa1aaa1aaaa1aaa1aaaaaa1aaaaa1aa1aaaaaa1a

etc.. I suspect this is due to a failing malloc() or something, but
It is silent failure. Apparently similar commands don't output "a"s,
e.g.​:

$ perl -we 'for || print "a" for 1..10'

It also affects different computers differently; the "x 10" needs to
be replaced by a higher value to get the same effect sometimes (but not
too high, or you'll fork-bomb your computer).

I believe this could be due to a bug in Perl; I have posted about it on
comp.lang.perl but received no response.

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl v5.6.0:

Configured by bod at Tue Feb 27 03:27:16 EST 2001.

Summary of my perl5 (revision 5.0 version 6 subversion 0) configuration:
  Platform:
    osname=linux, osvers=2.2.18, archname=i386-linux
    uname='linux duende 2.2.18 #1 thu dec 28 14:51:40 est 2000 i686 unknown '
    config_args='-Dccflags=-DDEBIAN -Darchname=i386-linux -Dprefix=/usr -Dprivlib=/usr/share/perl/5.6.0 -Darchlib=/usr/lib/perl/5.6.0 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.6.0 -Dsitearch=/usr/local/lib/perl/5.6.0 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dman1ext=1 -Dman3ext=3 -Dpager=/usr/bin/pager -Uafs -Ud_csh -Uusesfio -Duseshrplib -Dlibperl=libperl.so.5.6.0 -Dd_dosuid -des'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef
    useperlio=undef d_sfio=undef uselargefiles=define 
    use64bitint=undef use64bitall=undef uselongdouble=undef usesocks=undef
  Compiler:
    cc='cc', optimize='-O2', gccversion=2.95.3 20010219 (prerelease)
    cppflags='-DDEBIAN -fno-strict-aliasing -I/usr/local/include'
    ccflags ='-DDEBIAN -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
    stdchar='char', d_stdstdio=define, usevfork=false
    intsize=4, longsize=4, ptrsize=4, doublesize=8
    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, usemymalloc=n, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lnsl -ldl -lm -lc -lcrypt
    libc=/lib/libc-2.2.2.so, so=so, useshrplib=true, libperl=libperl.so.5.6.0
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:
    


@INC for perl v5.6.0:
    /usr/local/lib/perl/5.6.0
    /usr/local/share/perl/5.6.0
    /usr/lib/perl5
    /usr/share/perl5
    /usr/lib/perl/5.6.0
    /usr/share/perl/5.6.0
    /usr/lib/perl5/5.6/i386-linux
    /usr/lib/perl5/5.6
    /usr/lib/perl5/5.005/i386-linux
    .


Environment for perl v5.6.0:
    HOME=/home/dpc29
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/dpc29/bin:/usr/local/bin:/home/dpc29/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Nov 23, 2011

From @jkeenan

On Sat Apr 21 01​:36​:46 2001, dpc29@​cam.ac.uk wrote​:

$ perl -we 'fork || print for split //, "a" x 10'

when I run that on my computer, I get strange output. Instead of
printing "a" 2**10 times, the output contains random "1"'s, like this​:

aa1aaaaa1aaa1aaaaa1aaa1aaaa1aaa1aaaaaa1aaaaa1aa1aaaaaa1a

etc.. I suspect this is due to a failing malloc() or something, but
It is silent failure. Apparently similar commands don't output "a"s,
e.g.​:

$ perl -we 'for || print "a" for 1..10'

It also affects different computers differently; the "x 10" needs to

be replaced by a higher value to get the same effect sometimes (but
not
too high, or you'll fork-bomb your computer).

I have recently confirmed that this behavior still exists. It taught me
the meaning of 'fork-bomb'. :-(

Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Nov 23, 2011

From @arc

James E Keenan via RT <perlbug-followup@​perl.org> wrote​:

On Sat Apr 21 01​:36​:46 2001, dpc29@​cam.ac.uk wrote​:

$ perl -we 'fork || print for split //, "a" x 10'

when I run that on my computer, I get strange output.  Instead of
printing "a" 2**10 times, the output contains random "1"'s, like this​:

aa1aaaaa1aaa1aaaaa1aaa1aaaa1aaa1aaaaaa1aaaaa1aa1aaaaaa1a

It also affects different computers differently; the "x 10" needs to
be replaced by a higher value to get the same effect sometimes (but
not too high, or you'll fork-bomb your computer).

I have recently confirmed that this behavior still exists.  It taught me
the meaning of 'fork-bomb'. :-(

A hypothesis​: this is being run with an RLIMIT_NPROC in place (aka
`ulimit -u`). In particular, if RLIMIT_NPROC is at or near 2**n, then
some of the forks are likely to fail with EAGAIN when the literal 10
in the code is replaced with an integer >= n; whereas choosing a lower
number will make things work. That certainly matches the behaviour
I'm seeing. This slightly modified code should emit "a" in every
child process, "1" if the fork failed with EAGAIN, or "0" if the fork
failed for some other reason​:

$ ulimit -u
266
$ perl -MErrno=EAGAIN -we '(fork // print 0 + ($! == EAGAIN)) || print
for split //, "a" x 8'; sleep 0.2; echo
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1aa11a11a1aa11aa11aa11aaa1111aaaaa11aaaaaaaaaaaaaaaaaaaaaaaaaaaaa11aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

So when we can have just over 2**8 processes, and we try to start
(2**8)-1 in very quick succession, we get some EAGAIN failures, as
expected. If we try to start only (2**7)-1 processes, they all
succeed​:

$ perl -MErrno=EAGAIN -we '(fork // print 0 + ($! == EAGAIN)) || print
for split //, "a" x 7'; sleep 0.2; echo
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

But if we then reduce the ulimit again, we see more errors​:

$ ulimit -u 128
$ perl -MErrno=EAGAIN -we '(fork // print 0 + ($! == EAGAIN)) || print
for split //, "a" x 7'; sleep 0.2; echo
aaaa11a111111a1111111a1111a111111a1111a111a1

If I'm right about this, I don't think there's a bug here.

--
Aaron Crane ** http​://aaroncrane.co.uk/

@p5pRT
Copy link
Author

p5pRT commented Nov 23, 2011

From @ikegami

On Wed, Nov 23, 2011 at 5​:46 AM, Aaron Crane <perl@​aaroncrane.co.uk> wrote​:

James E Keenan via RT <perlbug-followup@​perl.org> wrote​:

On Sat Apr 21 01​:36​:46 2001, dpc29@​cam.ac.uk wrote​:

$ perl -we 'fork || print for split //, "a" x 10'

when I run that on my computer, I get strange output. Instead of
printing "a" 2**10 times, the output contains random "1"'s, like this​:

aa1aaaaa1aaa1aaaaa1aaa1aaaa1aaa1aaaaaa1aaaaa1aa1aaaaaa1a

It also affects different computers differently; the "x 10" needs to
be replaced by a higher value to get the same effect sometimes (but
not too high, or you'll fork-bomb your computer).

I have recently confirmed that this behavior still exists. It taught me
the meaning of 'fork-bomb'. :-(

A hypothesis​: this is being run with an RLIMIT_NPROC in place (aka
`ulimit -u`). In particular, if RLIMIT_NPROC is at or near 2**n, then
some of the forks are likely to fail with EAGAIN when the literal 10
in the code is replaced with an integer >= n; whereas choosing a lower
number will make things work. That certainly matches the behaviour
I'm seeing. This slightly modified code should emit "a" in every
child process, "1" if the fork failed with EAGAIN, or "0" if the fork
failed for some other reason​:

I'm not clear on why fork failing would cause $_ to be changed from 'a' to
1.

Your code is actually significantly different as the ones output by your
code originate from a print the OP did not have.

@p5pRT
Copy link
Author

p5pRT commented Nov 23, 2011

From Eirik-Berg.Hanssen@allverden.no

On Wed, Nov 23, 2011 at 8​:12 PM, Eric Brine <ikegami@​adaelis.com> wrote​:

I'm not clear on why fork failing would cause $_ to be changed from 'a' to
1.

  Me neither, but it does. Or rather, evaluating the fork in a boolean
context does ...

eirik@​bluebird[20​:22​:14]/tmp$ ulimit -u 130
eirik@​bluebird[20​:22​:19]
/tmp$ perl -we '!fork, print for split //, "a" x
10' ; sleep 1; echo
Useless use of not in void context at -e line 1.
aaaaaaaaa1
eirik@​bluebird[20​:22​:22]~/tmp$ perl -we 'fork, print for split //, "a" x
10' ; sleep 1; echo
aaaaaaaaaUse of uninitialized value in print at -e line 1.

eirik@​bluebird[20​:22​:38]~/tmp$

  Funny? :)

Eirik

@p5pRT
Copy link
Author

p5pRT commented Nov 23, 2011

From sidhekin@allverden.no

On Wed, Nov 23, 2011 at 8​:24 PM, Eirik Berg Hanssen <
Eirik-Berg.Hanssen@​allverden.no> wrote​:

On Wed, Nov 23, 2011 at 8​:12 PM, Eric Brine <ikegami@​adaelis.com> wrote​:

I'm not clear on why fork failing would cause $_ to be changed from 'a'
to 1.

Me neither, but it does. Or rather, evaluating the fork in a boolean
context does ...

  ... err, no, let's try again ... fork failing causes $_ to be changed
from 'a' to undef. Evaluatin the fork in a boolean context changes it
(most likely further? or possibly instead?) to 1.

eirik@​bluebird[20​:22​:14]/tmp$ ulimit -u 130
eirik@​bluebird[20​:22​:19]
/tmp$ perl -we '!fork, print for split //, "a" x
10' ; sleep 1; echo
Useless use of not in void context at -e line 1.
aaaaaaaaa1
eirik@​bluebird[20​:22​:22]~/tmp$ perl -we 'fork, print for split //, "a" x
10' ; sleep 1; echo
aaaaaaaaaUse of uninitialized value in print at -e line 1.

eirik@​bluebird[20​:22​:38]~/tmp$

  Ayup.

Eirik

@p5pRT
Copy link
Author

p5pRT commented Nov 23, 2011

From @ikegami

On Wed, Nov 23, 2011 at 2​:27 PM, The Sidhekin <sidhekin@​allverden.no> wrote​:

On Wed, Nov 23, 2011 at 8​:24 PM, Eirik Berg Hanssen <
Eirik-Berg.Hanssen@​allverden.no> wrote​:

On Wed, Nov 23, 2011 at 8​:12 PM, Eric Brine <ikegami@​adaelis.com> wrote​:

I'm not clear on why fork failing would cause $_ to be changed from 'a'
to 1.

Me neither, but it does. Or rather, evaluating the fork in a boolean
context does ...

... err, no, let's try again ... fork failing causes $_ to be changed
from 'a' to undef. Evaluatin the fork in a boolean context changes it
(most likely further? or possibly instead?) to 1.

That's gotta be a bug.

What's really funny is changing from print to Devel​::Peek's Dump($_) only
reveals "a".

Is $_ being changed, or is it stack corruption?

@p5pRT
Copy link
Author

p5pRT commented Nov 24, 2011

From @arc

Eric Brine <ikegami@​adaelis.com> wrote​:

I'm not clear on why fork failing would cause $_ to be changed from 'a' to
1.

Uh, yes. Sorry, don't know what I was thinking there.

--
Aaron Crane ** http​://aaroncrane.co.uk/

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

2 participants