Shifting error codes

M

Marc Girod

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
 
J

Jens Thoms Toerring

Marc Girod said:
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
 
A

Alan Curry

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


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.
 
A

Alan Curry

Quoth (e-mail address removed) (Alan Curry):

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.
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.
 
A

Alan Curry

Quoth (e-mail address removed) (Alan Curry):

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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top