Shifting error codes

Discussion in 'Perl Misc' started by Marc Girod, Oct 25, 2009.

  1. Marc Girod

    Marc Girod Guest

    Hi,

    The code I maintain used to shift values meant as exit codes.

    # Shift the status up so it looks like an exit status.
    $rc = $2 << 8;

    This practice seemed justified by the paragraph on $? in perlvar,
    although, and this is my question, I am not sure how to read it
    anymore.

    I found that the return codes were not as expected:

    $ perl -e 'exit 255'; echo $?
    255
    $ perl -e 'exit 256'; echo $?
    0

    So, should one ever shift codes leftwards,
    or only rightwards codes received from sub-processes?

    Thanks,
    Marc
    Marc Girod, Oct 25, 2009
    #1
    1. Advertising

  2. Marc Girod <> wrote:
    > The code I maintain used to shift values meant as exit codes.


    > # Shift the status up so it looks like an exit status.
    > $rc = $2 << 8;


    > This practice seemed justified by the paragraph on $? in perlvar,
    > although, and this is my question, I am not sure how to read it
    > anymore.


    > I found that the return codes were not as expected:


    > $ perl -e 'exit 255'; echo $?
    > 255
    > $ perl -e 'exit 256'; echo $?
    > 0


    Looks like you're on some kind of UNIX. And on UNIX the exit
    value of a program is the lowest 8 bits of the return status
    value only (i.e. a value between 0 and 255), higher bits being
    used for information why the process stopped (e.g. normally by
    calling exit() or because it was killed due to a signal etc.).
    IIRC, higher order bits in the value passed to exit() simply
    get masked out, so they don't make it through to '$?'.

    > So, should one ever shift codes leftwards,


    As long as you can guarantee that the result isn't larger
    than 255 it's ok, otherwise things won't work as expected.

    > or only rightwards codes received from sub-processes?


    Sorry, but I don't understand what's meant by this.

    Regards, Jens
    --
    \ Jens Thoms Toerring ___
    \__________________________ http://toerring.de
    Jens Thoms Toerring, Oct 25, 2009
    #2
    1. Advertising

  3. Marc Girod

    Alan Curry Guest

    In article <-berlin.de>,
    Jens Thoms Toerring <> wrote:
    >Marc Girod <> wrote:
    >
    >As long as you can guarantee that the result isn't larger
    >than 255 it's ok, otherwise things won't work as expected.
    >
    >> or only rightwards codes received from sub-processes?

    >
    >Sorry, but I don't understand what's meant by this.


    He means the return value from perl's system(). perlfunc says:

    The return value is the exit status of the program as returned
    by the "wait" call. To get the actual exit value, shift right
    by eight (see below).

    I assume that this evil magic number is a leftover from perl's early years
    when there were no modules, and no easy way to make the system's WIFEXITED,
    WEXITSTATUS, and related macros available inside a perl script. Does anybody
    know what might happen if you compiled perl on a POSIX system that didn't use
    the same bit layout for an exit status? Would it translate the status code,
    possibly losing information along the way if some of the bitfields are
    differently sized? Or does it just give you the raw number, and let you trip
    over the bad advice in perlfunc? Either way, something is wrong here.

    Better just treat the return value of system() as a boolean and check
    ${^CHILD_ERROR_NATIVE} if you need details. At least it has reasonable
    documented behavior.

    --
    Alan Curry
    Alan Curry, Oct 25, 2009
    #3
  4. Marc Girod

    Alan Curry Guest

    In article <>,
    Ben Morrow <> wrote:
    >
    >Quoth (Alan Curry):
    >>
    >> I assume that this evil magic number is a leftover from perl's early years
    >> when there were no modules, and no easy way to make the system's WIFEXITED,
    >> WEXITSTATUS, and related macros available inside a perl script. Does anybody
    >> know what might happen if you compiled perl on a POSIX system that didn't use
    >> the same bit layout for an exit status? Would it translate the status code,
    >> possibly losing information along the way if some of the bitfields are
    >> differently sized? Or does it just give you the raw number, and let you trip
    >> over the bad advice in perlfunc? Either way, something is wrong here.

    >
    >Check the source :). This has changed over the years, largely as a
    >result of pressure from the VMS people (VMS has W*, but doesn't use exit
    >codes looking anything like the POSIX ones). It turned out to be easier
    >to fix perl than to fix all the scripts assuming Unix semantics for $?.


    Unix semantics? The Unix definition is here:

    http://www.opengroup.org/onlinepubs/9699919799/functions/waitpid.html

    And that definition doesn't mandate any particular arrangement of bits. Unix
    requires the use of W*() macros to examine an exit code, unless you're just
    comparing it to 0 which is a special value.

    "Shift by 8" is unwarranted chumminess with the implementation, as wrong as
    hardcoding an assumption that EAGAIN==11, or O_NONBLOCK==0x800, or LOCK_EX==2
    which used to also be encouraged by perlfunc, and is still sort of implied
    to be correct there. (I wonder if that's subject to translation too)

    >
    >Current behaviour is to extract the relevant bits using the proper W*
    >macros and then build up a fake $? value that looks the way you would
    >expect. ${^C_E_N} is there in case you need the *actual* return value.


    I see now that this is better documented in the perlvar entry for $?.
    Before, I was looking at the perlfunc entry for system(). I don't see
    anything that explicitly says the value returned by system is the same value
    that gets put into $?. They're both described in similar terms, and they're
    obviously strongly related, but since at least one of them is being mangled
    from native format to "shift by 8" format, the situation is still not clear.

    >
    >> Better just treat the return value of system() as a boolean and check
    >> ${^CHILD_ERROR_NATIVE} if you need details. At least it has reasonable
    >> documented behavior.

    >
    >It's documented that ($? >> 8) will be the lowest 8 bits of the process'
    >exit value. The signal and core stuff is non-portable, but then that's
    >to be expected. (It will be correct if the OS provides reasonable
    >definitions of the WTERMSIG and WCOREDUMP macros.)


    So the you can litter your code with magic numebrs that match the magic
    numbers that perl puts into $? or you can write something readable instead,
    and as a bonus get the un-truncated exit value, by using
    ${^CHILD_ERROR_NATIVE} and the POSIX module.

    But wait... according to the POSIX module's man page:

    WEXITSTATUS WEXITSTATUS($?) returns the normal exit status
    of the child process (only meaningful if
    WIFEXITED($?) is true)

    I hope that's a documentation bug. I hope it should really be
    WEXITSTATUS(${^CHILD_ERROR_NATIVE}). Or does the POSIX module's WEXITSTATUS()
    not actually do the same thing as the C-level WEXITSTATUS(), does it actually
    expect the perl-mangled $? variable instead of the real status code? If that
    documentation is correct, then I can see no way at all to portably get a
    child process's full exit status in perl. What a clusterfsck.

    --
    Alan Curry
    Alan Curry, Oct 26, 2009
    #4
  5. Marc Girod

    Alan Curry Guest

    In article <>,
    Ben Morrow <> wrote:
    >
    >Quoth (Alan Curry):
    >> In article <>,
    >> Ben Morrow <> wrote:
    >> >Check the source :). This has changed over the years, largely as a
    >> >result of pressure from the VMS people (VMS has W*, but doesn't use exit
    >> >codes looking anything like the POSIX ones). It turned out to be easier
    >> >to fix perl than to fix all the scripts assuming Unix semantics for $?.

    >>
    >> Unix semantics? The Unix definition is here:
    >>
    >> http://www.opengroup.org/onlinepubs/9699919799/functions/waitpid.html
    >>
    >> And that definition doesn't mandate any particular arrangement of bits. Unix
    >> requires the use of W*() macros to examine an exit code, unless you're just
    >> comparing it to 0 which is a special value.

    >
    >Unix is not POSIX, nor is it XPG (trademarks aside). There are a lot of


    So what you meant by "Unix semantics" as applied to system()/wait() then is
    in fact "bit-for-bit compatibility with V7"? I'm not sure that's a better
    definition than what the IEEE/OpenGroup people have come up with.

    [...]
    >macro, which I suspect won't work at all. (It seems that the only
    >systems Perl supports that *don't* use 'normal' exit statusseses are VMS
    >and BeOS/Haiku.)


    Rampant binary compatibility allows you to get away with hardcoded magic
    numbers instead of using the proper abstractions. This is great if you're a
    sloppy coder, not so much if you're trying to do the right thing.

    --
    Alan Curry
    Alan Curry, Oct 26, 2009
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. walala
    Replies:
    3
    Views:
    5,320
    Brent Hayhoe
    Nov 21, 2003
  2. Stefan Duenser

    Basic shifting question

    Stefan Duenser, Dec 7, 2004, in forum: VHDL
    Replies:
    4
    Views:
    432
    Stefan Duenser
    Dec 8, 2004
  3. Greg  --
    Replies:
    4
    Views:
    2,137
  4. Replies:
    2
    Views:
    2,798
    Malcolm
    Aug 20, 2005
  5. Allen
    Replies:
    1
    Views:
    627
    Mark Rae [MVP]
    Dec 3, 2007
Loading...

Share This Page