LeFebvre.wbst@XEROX.ARPA (08/06/84)
> The solution would seem to be to have the C signal handling mechanism > save errno before calling the signal routine and restore it after > the routine has returned. Alternatively (actually, in lieu of), the signal handling routine itself could save and restore the value of errno. It is possible to assign errno a value explicitly. The routine "i" in your example could be written: void i() { int olderrno; /* note the name is exactly 8 characters :-) */ olderrno = errno; signal(SIGALRM,i); open(".",1); /* Fails, since is a directory */ errno = olderrno; } Of course, you also have to move the definition of errno to before the "void i" statement. William LeFebvre Department of Computer Science Rice University At Xerox for the summer (but not much longer)
ka@hou3c.UUCP (Kenneth Almquist) (08/06/84)
The global 'errno' variable set by the assembler routines in the C library for system-call interface can be garbled before the program gets to look at it if a signal arrives and the signal-handling routine does another system call (which gets an error). This is a specific case of a general problem with signal handlers that modify global or static variables. For example, a call to malloc in a signal handler can result in a corrupted free space list. Radford suggests that the signal mechanism should save and restore the value of errno, but the only solution to the general problem is care on the part of the programmer. One way to fix Radford's example is to have the alarm routine simply set a flag for later processing. The code becomes: static int alflag; /* set when alarm signal received */ void i() { /* called on alarm signal */ alflag++; } void testalarm() { /* called from loop in main routine */ if (alflag) { alflag = 0; signal(SIGALARM, i); alarm(1); open(".", 1); /* this will fail */ } } Another fix would of course be to have the routine "i" save and restore the value of errno. Kenneth Almquist
rml@hpfcls.UUCP (rml) (08/15/84)
> The solution would seem to be to have the C signal handling mechanism > save errno before calling the signal routine and restore it after > the routine has returned. This is impossible with the standard implementation of the system call interface and errno. Errno is is an arbitrary location in the user's address space which is unknown to the kernel. That's why the kernel passes the errno value back in a register and an assembly language library routine copies the value to the global variable. If this problem is a concern for you, you can simulate your suggested solution in your own signal handler: void i() { int save_errno; extern int errno; save_errno = errno; signal(SIGALRM,i); alarm(1); open(".",1); /* Fails, since is a directory */ errno = save_errno; } > Is the fact that this bug has been present for upwards of ten years > in all versions of Unix, apparently without anyone noticing, an > indication of how often Unix programmers check for errors? The fact that you can cause this behavior about once a minute with a contrived example does not indicate that this is a serious problem. Admittedly, many programs running on UNIX* systems (including a number of commands shipped with UNIX systems) are lax about checking for errors in system calls or about reporting the reason for the error when they do check. However, the fact that a simple workaround exists for those programmers who are concerned is a point in favor of UNIX systems. Bob Lenk {hplabs, ihnp4}!hpfcla!rml *UNIX is a trademark of AT&T Bell Laboratories