Package: perl Version: 5.20.2-6 See transcripts below.
Perl's system builtin needs to fork and exec. If the exec fails it needs to print a message to stderr and exit. It appears that this is implemented in Perl and that it does the latter with sysexit, but the former with warn. This has a number of strange effects, which are visible if a $SIG{__WARN__} handler is installed. Ones which can be observed below include: * If $SIG{__WARN__} = sub { die $_[0]; } (or something else that raises an exception) then the control flow escapes from the confines of system, and avoids the sysexit. The program's END blocks might be executed, for example. * Worse, if the program has its own exception handler surrounding system, it will now start executing the main program both in the parent and in the child. * During the $SIG{__WARN__} handler, the Perl interpreter is not properly set up in all versions of Perl. For example in 5.14.2-21+deb7u2, $$ is a lie - it still refers to the parent process. * Something else weird seems to be going on. I find these two messages in the transcript below hard to explain: 24633 GOT UNDEF EVAL at ./t.pl line 15. 24633 BARE at ./t.pl line 21. It appears that something is discarding or squashing an error. The latter is particularly puzzling because $@ is left as "" (indicating that the eval did not catch an exception) but $y is not set to 42 (indicating that the eval did not run to completion). I suggest the following remedies, in combination: * system() should reset $SIG{__WARN__} in the child. There should be a way to set $SIG{__WARN__} within system's child, but it should be separate. $SIG{__WARN_CHILD__} or something maybe. * The behaviour should be documented. * The fact that $$ was wrong should be written down somewhere in the manual so that users use the correct workaround (see below). * And ideally someone familiar with the implementation should satisfy themselves that they understand the currently observed behaviour, so that we are confident that there aren't other lurking oddities. As a workaround, people using unfixed versions of Perl can write: my $mainprogram = $$; $SIG{__WARN__} = sub { die $_[0] unless getppid == $mainprogram; }; Note that `die $_[0] if $$ == $mainprogram' is ineffective because $$ is wrong. Thanks, Ian. (build)ian@zealot:~/junk$ cat t.pl #!/usr/bin/perl -w use strict; use POSIX; $SIG{__WARN__} = sub { die "DYING DUE TO WARNING $_[0]"; }; END { print STDERR "wheee!\n" if getppid == $$; } END { print STDERR "getppid= ", getppid, "\n"; } END { print STDERR "\$\$= $$\n"; } my @bad = qw(/dev/enoent nothing); print STDERR "---------- 1 ".getppid." $$ ----------\n"; my $y = eval { system @bad and die "EVAL $!"; 42; }; $y //= 'UNDEF'; print STDERR getppid." GOT $y $@\n"; print STDERR "---------- 2 ".getppid." ----------\n"; system @bad and die getppid." BARE $!"; print STDERR "NOTREACHED\n"; (build)ian@zealot:~/junk$ ./t.pl ---------- 1 24633 24948 ---------- 24948 GOT UNDEF DYING DUE TO WARNING Can't exec "/dev/enoent": No such file or directory at ./t.pl line 15. ---------- 2 24948 ---------- DYING DUE TO WARNING Can't exec "/dev/enoent": No such file or directory at ./t.pl line 21. $$= 24950 getppid= 24949 24948 BARE No such file or directory at ./t.pl line 21. $$= 24949 getppid= 24948 24633 GOT UNDEF EVAL at ./t.pl line 15. ---------- 2 24633 ---------- DYING DUE TO WARNING Can't exec "/dev/enoent": No such file or directory at ./t.pl line 21. $$= 24951 getppid= 24948 24633 BARE at ./t.pl line 21. $$= 24948 getppid= 24633 (build)ian@zealot:~/junk$ zealot:~/junk> ./t.pl ---------- 1 23655 24976 ---------- 24976 GOT UNDEF DYING DUE TO WARNING Can't exec "/dev/enoent": No such file or directory at ./t.pl line 15. ---------- 2 24976 ---------- DYING DUE TO WARNING Can't exec "/dev/enoent": No such file or directory at ./t.pl line 21. $$= 24976 getppid= 24978 24976 BARE No such file or directory at ./t.pl line 21. $$= 24976 getppid= 24976 wheee! 23655 GOT UNDEF EVAL at ./t.pl line 15. ---------- 2 23655 ---------- DYING DUE TO WARNING Can't exec "/dev/enoent": No such file or directory at ./t.pl line 21. $$= 24976 getppid= 24976 wheee! 23655 BARE at ./t.pl line 21. $$= 24976 getppid= 23655 zealot:~/junk> -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org