[comp.lang.c] signal & sigvec error return codes

lijewski@batcomputer.tn.cornell.edu (Mike Lijewski) (05/25/89)

     Do all vendors still document the return code of signal and
sigvec as being -1 (implicitely an int)?  My problem with this is
that if you try to be a "good" programmer and check for an error as
in 
    if(signal(SIGINT, SIG_IGN) == -1){
      perror("signal");
      exit(1);
    }

say, you will either get a warning or an error, depending on how smart
your compiler is.  Why not document the error return as being something
along the lines of SIG_ERR, where SIG_ERR is defined as

#define SIG_ERR ((int(*)())-1)

in <signal.h>?

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/25/89)

In article <8044@batcomputer.tn.cornell.edu> lijewski@batcomputer.tn.cornell.edu (Mike Lijewski) writes:
>Why not document the error return as being something
>along the lines of SIG_ERR, where SIG_ERR is defined as
>#define SIG_ERR ((int(*)())-1)
>in <signal.h>?

That's exactly what pANSI X3.159 requires (the macro, not the
particular value), except you have the type wrong -- it should be
((void(*)())-1).  Some older <signal.h>s also use the wrong types;
we got AT&T to fix theirs with SVR3, and other vendors will also need
to straighten this out for ANSI C and POSIX conformance.

Since you can't count on SIG_ERR being defined by non-ANSI <signal.h>,
what you should write is
	#include <signal.h>
	#ifndef SIG_ERR	/* assume the traditional implementation */
	#define SIG_ERR ((void(*)())-1)
	#endif

karl@haddock.ima.isc.com (Karl Heuer) (05/26/89)

In article <10319@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <8044@batcomputer.tn.cornell.edu> lijewski@batcomputer.tn.cornell.edu (Mike Lijewski) writes:
>>Why not document the error return as being something [like]
>>#define SIG_ERR ((int(*)())-1)
>
>That's exactly what pANSI X3.159 requires (the macro, not the particular
>value), except you have the type wrong -- it should be ((void(*)())-1).

Actually, it's ((void (*)(int))-1), but the above is the next best
approximation if you don't have prototypes.

Interestingly, though, certain implementations that provide the "software
signal" package (gsignal/ssignal) now have a problem, because this package
really does use int-valued handlers.  (The return value is examined by the
implementation, to decide whether the condition has been properly handled.)
Unfortunately, they also attempt to use the same header file and macro names,
so there's a type clash.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

diamond@diamond.csl.sony.junet (Norman Diamond) (05/26/89)

In article <8044@batcomputer.tn.cornell.edu> lijewski@batcomputer.tn.cornell.edu (Mike Lijewski) writes:

>     Do all vendors still document the return code of signal and
>sigvec as being -1 (implicitly an int)?

Probably not -- but you do need to know that it is implicitly an int.

>My problem with this is
>that if you try to be a "good" programmer and check for an error as
>in 
>    if(signal(SIGINT, SIG_IGN) == -1){
>      perror("signal");
>      exit(1);
>    }
>say, you will either get a warning or an error, depending on how smart
>your compiler is.

In order to do this test properly, maybe it is necessary to cast the
result of signal to an (int), and compare to -1.  After all, the value
of an int does not have to be divisible by 4.  Though I still wonder,
since signal is returning a pointer to a function, how does signal get
a -1 into that address register without aborting (on some machines).

>Why not document the error return as being something
>along the lines of SIG_ERR, where SIG_ERR is defined as
>
>#define SIG_ERR ((int(*)())-1)
>
>in <signal.h>?

SIG_IGN has this definition in <signal.h>, last time I looked.  And
now, besides wondering how signal gets a wierd address into a certain
register, I also wonder how the cast does it in the compiled code.
Why doesn't the compiled code abort?  Why doesn't the compiler notice
that an odd address cannot be a function pointer?  In short, why does
this work?  (Also, does ANSI require such nonsense to work, does ANSI
require exceptions to be permitted to the usual rules for pointers,
or can <signal.h> define values that are at least aligned, even if not
guaranteed to be in a legal segment.....)

--
Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.co.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-implementing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/28/89)

In article <10287@socslgw.csl.sony.JUNET> diamond@csl.sony.junet (Norman Diamond) writes:
>In article <8044@batcomputer.tn.cornell.edu> lijewski@batcomputer.tn.cornell.edu (Mike Lijewski) writes:
>In order to do this test properly, maybe it is necessary to cast the
>result of signal to an (int), and compare to -1.

No!  The same problem arises on UNIX systems where the result of sbrk()
is being tested.  These functions return error indications that, when
they can be expressed in C at all, have the form ((some_pointer)-1).
That is what you should test for; not all implementations permit
pointers to be cast to ordinary (int).

The real solution is for some system header to define a macro, like
SIG_ERR, for use in performing such tests in your application source.
On some architectures the value of such a macro may have nothing to
do with "-1" in any form.  SIG_ERR can always be implemented, e.g.:
	/* <signal.h>: */
	/* ... */
	extern void __dummy(int);	/* in C run-time library */
	#define SIG_ERR __dummy

>Why doesn't the compiled code abort?  Why doesn't the compiler notice
>that an odd address cannot be a function pointer?  In short, why does
>this work?  (Also, does ANSI require such nonsense to work, does ANSI
>require exceptions to be permitted to the usual rules for pointers,
>or can <signal.h> define values that are at least aligned, ...

The C Standard certainly does not require that an arbitrary integer
can be successfully cast to a pointer.  The rules for when this works
and when it doesn't are up to the implementation.  Many byte-addressable
architecture implementations of C permit casting arbitrary integers to
pointers, although an attempt to actually access a function or object
via a garbage pointer value may very well fail.

tps@chem.ucsd.edu (Tom Stockfisch) (05/28/89)

In article <8044@batcomputer.tn.cornell.edu> lijewski@batcomputer.tn.cornell.edu (Mike Lijewski) writes:
_     Do all vendors still document the return code of signal and
_sigvec as being -1 (implicitely an int)?  My problem with this is
_that if you try to be a "good" programmer and check for an error as
_in 
_    if(signal(SIGINT, SIG_IGN) == -1){
_      perror("signal");
_      exit(1);
_    }
_say, you will either get a warning or an error, depending on how smart
_your compiler is.  Why not document the error return as being something
_along the lines of SIG_ERR, where SIG_ERR is defined as
_#define SIG_ERR ((int(*)())-1)
_in <signal.h>?

This last cast gets warnings from many compilers (e.g. gcc).

Why isn't this implemented without the potentially unportable
and kludgey cast of -1?

signal.h:
	int	SIG_ERR(), SIG_IGN(), SIG_DFL();

signal.c:
	int	SIG_ERR(){assert(0);}
	int	SIG_IGN(){assert(0);}
	int	SIG_DFL(){assert(0);}
-- 

|| Tom Stockfisch, UCSD Chemistry	tps@chem.ucsd.edu