lakshmananindia has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,
use strict; use warnings; sub handler { open FH,">a"; print FH @_; } $SIG{__DIE__}=\&handler; close STDERR; die "Exit from the program";
I executed the above code and I put "cat a"
I shows the following,
Exit from the program at a.pl line 31.
Exit from the program at a.pl line 31.

I expected only one line, but it has 2 lines.

If I remove the close STDERR statement then my file contains only one line.

I checked with perl -d. The handler is called only once.

Why it is printing twice when "close STDERR" is there?

Replies are listed 'Best First'.
Re: Log message in Die handler
by zwon (Abbot) on Jan 16, 2009 at 12:42 UTC

    Because when you open a in handler it opens file and assigns to it descriptor with first available number -- 2 (STDERR).

    Update: try this:

    #!/usr/bin/perl use strict; use warnings; close STDERR; open FH, '>', 'log'; die "exit from program\n";

    Update2: or more correct method:

    #!/usr/bin/perl use strict; use warnings; use POSIX qw(dup2); open FH, '>', 'log'; dup2(fileno FH, 2); die "exit from program\n";

    But actually I prefer using Log::Log4perl and its logdie method.

    Update3: uhm, I just discovered, that when you open STDERR perl always assigns it to descriptor 2:

    #!/usr/bin/perl use strict; use warnings; use POSIX qw(dup2); open FH, '>', 'log'; dup2(fileno FH, 2); open STDERR, '>', 'stderr'; # this would be placed into 'stderr', not into 'log' warn "STDERR descriptor is:", fileno(STDERR), "\n"; die "exit from program\n";

      Good grief. This seems to imply that if you close STDERR then die (and other diagnostics ?) will happily be written to whatever happens to be attached as descriptor 2 ?

      If so, then the trick appears to be to open STDERR '>', '/dev/nul', or something else to occupy descriptor 2 to squelch output ? Thinking about a more portable solution I tried:

      use strict ; use warnings ; sub die_handler { open FH, ">&1"; print FH "die_handler: ", @_ ; } ; $SIG{__DIE__} = \&die_handler ; close STDERR ; open STDERR, '<', \'' ; die "Oh shoot !" ;
      which appears to do the trick. Noting that the close STDERR is required.

Re: Log message in Die handler
by almut (Canon) on Jan 16, 2009 at 13:45 UTC

    You could close FH in the handler, in which case the subsequent output to stderr (produced by the die statement the usual way) won't end up anywhere, neither in the file 'a', nor on stderr, because file descriptor 2 (which is used for both FH and STDERR in this case — as zwon pointed out) would then no longer be open at that point in time.  Or, as oshalla suggested, simply reopen STDERR to /dev/null.

Re: Log message in Die handler
by ack (Deacon) on Jan 16, 2009 at 16:16 UTC

    I just tried the code and, as one would expect, got the same as lakslunananindia. But if I close FD within the sub handler(), after wrting to it, then it looks like the problem is also solved without fiddling with STDERR so much.

    Is there something wrong with closing FD in the signal handler?

    I don't have any real experience with signal handlers (though by now I should have had some experience); but coincidentally, I just began exploring them a couple of months ago. I don't get many opportunities to do much exploration, though. So this little node is most instructive for me.

    Thanks, all.

    ack Albuquerque, NM
Re: Log message in Die handler
by targetsmart (Curate) on Jan 17, 2009 at 15:45 UTC
    Its interesting, so I did my part of checking. see the below code
    perl -e 'BEGIN{close(STDERR)};open FH,">log"; die 'testing';'
    in begin, the STDERR is closed, so no more STDERR(fd 2)
    but when 'open FH' is seen, the kernel is trying to allocate the unused file descriptor from starting from 0, now 2 is free, so it is allocated.
    when the die executes, it might be a problem with die, it might be programmed to write to fd 2 always, regardless of pointing to STDERR or any other file.
    after this code, you can expect the error to be logged in file 'log'.
    'perldoc -f die' has no clues on this, it says that 'die prints to STDERR'
    (assuming it is always fd 2) Interesting...