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

I wonder if I am misreading something, but I believe I have found a bug in Carp. My development group regularly uses exit status to report error conditions to parent programs. This is because we do TN3270 screen scraping and certain conditions (host timeout, connection refused, etc.) cause an automatic restart of the programs. When we began moving our programs to perl, the restarting stopped working. After some searching, I found the problem was Carp. I have found this problem in both 5.6.1 and 5.8.1.

Compare the two snippets and their outputs.

Using die:
#!/appl/cpc/bin/perl -w use strict; use warnings; $! = 10; $? = 9; die "$!: $?";

xxx:xxx/xxx/xxx> perl5.8.1 test.pl; echo $?
No child processes: 9 at test.pl line 7.
10

Using croak:
#!/appl/cpc/bin/perl -w use strict; use warnings; use Carp; $!=10; $?=9; croak "$!: $?";

xxx:/xxx/xxx/xxx> perl5.8.1 test.pl; echo $?
No child processes: 9 at test.pl line 9
255

Scanning through the code for Carp, I can't (offhand) see anything that might be causing this. I vaguely suspect this from Carp.pm:
{ local $@; require Carp::Heavy; } # XXX fix require to not clear $ +@?

But those suspicions are mostly because I have no clue and am grasping at anything that looks vaguely weird. Is this a valid bug to report or am I missing something?

For reference, this is compiled for 'HP-UX B.11.00 E'. I can post the 'perl -V' if necessary.

Replies are listed 'Best First'.
Re: Bug with Carp and $!/$?
by halley (Prior) on Jul 10, 2003 at 17:14 UTC

    Yes, perlvar states that you "can set $!" if you want to set the exit code for a subsequent die(). Croak would seem on its face to be a natural extension to die, and maybe should support the propagation of numeric $!.

    However, I would expect that if you really want to send a specific numerical exit code, that you do so forcefully and legibly, so that future folks really understand that the exit code is important. There are a lot of magic variables which people think of as "read-only," and before I checked, I thought $! was one of them.

    carp "Why I'm crashing"; exit(10);

    Even if you don't agree that this is more readable, it should be a proper work-around for you. The case where this wouldn't work is if your caller is trying to use eval in the eval/die exception-throwing model.

    --
    [ e d @ h a l l e y . c c ]

Re: Bug with Carp and $!/$?
by tilly (Archbishop) on Jul 10, 2003 at 17:30 UTC
    You can report this to p5p with the perlbug utility.

    My educated guess is that the problem is that $! gets set by the last failed system call. Normal Perl code generates a lot of harmless failures, and so you should not expect to have $! mean anything specific unless something just failed.

    The flip side of that is that you should not expect $!'s value to be maintained through any complex code, such as the internals of Carp unless a specific effort is made to do so.

      Good point, I never thought about that. I wonder if the documentation for Carp can be patched to recognize this caveat. Would that go in perlbug as well?

      Thanks a lot for your help, everyone. You've helped me keep my exit conditions and my beloved Carp :)

Re: Bug with Carp and $!/$?
by Kageneko (Scribe) on Jul 10, 2003 at 17:37 UTC
    After reading about die a bit more, I changed the code to use:
    $? = (9 << 8);
    THAT worked, although I find it kind of annoying. However, since we use constants for all of our exit conditions (RC_HOST_TIMEOUT, etc.), then I can just put that in the constant and forget about it. :)
Re: Bug with Carp and $!/$?
by Anonymous Monk on Jul 10, 2003 at 17:22 UTC
    I'm not sure what seems weird to you, the Perl error message or the printing of the number 255. If the former, it's not a bug: $? refers to the error message of a child process which you did not spawn before printing it. So although you explicitly set the variable, I am not terribly surprised that Perl complained and you didn't get the value of $? printed out. As for the 255, I *think* that I vaguely remember (how's that for a disclaimer) mention on this site of Perl (or was it Carp specifically?) defaulting to octal 255 in some situations, but uselessly enough, I can't recall anything of the context of that thread, others I'm sure can enlighten both of us.
      Oh, I expected to get the value of $! (which I set to 10). The reason I set $? is that the 'die' manpage states:

      Outside an "eval", prints the value of LIST to "STDERR" and exits with the current value of $! (errno). If $! is 0, exits with the value of "($? >> 8)" (backtick `command` status). If "($? >> 8)" is 0, exits with 255.

      I was trying to make sure that $? would be non-zero, although it just occurred to me that I should've done something like: $? = (9 << 8) in order for that to work.
Re: Bug with Carp and $!/$?
by tilly (Archbishop) on Jul 14, 2003 at 01:14 UTC
    I just randomly thought about this again today, and I think I know why $! got reset, and I believe that you are right about the cause.

    The require line that you finger is Perl's delayed loading of Carp::Heavy. Loading that involves I/O, compilation, etc. All of which are likely to reset $!.

    And indeed you can test it with comparing the output of the following script:

    #!/appl/cpc/bin/perl -w use strict; use warnings; use Carp; require Carp::Heavy; # Avoid delayed loading resetting $! $!=10; $?=9; croak "$!: $?";
    All things considered I don't think your assumption about Carp was off base. (It was wrong, it is undocumented, but it is a reasonable and possibly useful feature.) I would suggest submitting a patch to Carp that captures $! before the require and then resets it afterwards. Also create a test that checks that $! is preseved through a croak and a confess and submit that as well.