APPENDIX A

List of Warnings.

The shadow-byte administration makes it possible to check for a wide range of errors during run-time. We have tried to make the diagnostics self-explanatory and especially useful for the C-programmer. The warnings are printed in the message file, together with source file and line number. The complete list of warnings is presented here, followed by an explanation of what might be wrong. Often, these explanations implicitly assume that the program being interpreted, was originally written in C (and not Pascal, Basic etc.).

Reading the load file The interpreter was compiled with the NOFLOAT option; code involving floating point operations can be run as long as the actual instructions are avoided. The interpreter already tests anything conceivable. This number could be used to allocate tables for tallying; these tables are, however, expanded as needed, so the number is immaterial. The loadfile contains a floating point denotation which does not satisfy the syntax (see 2.6). Examining the loadfile (with od -c) might show the syntax error. Probably there is a bug in the front-end, creating floats with a bad syntax.

System calls The second parameter to the ioctl() request (the operation code) is invalid or not implemented; since there are many different opcodes on the various UNIX systems, it is difficult to tell which. The system call fails. The monitor calls mpxcall(), profil() and ptrace() have not been implemented. The monitor call fails. Bad pointers passed to system calls do not cause a memory fault (which in UNIX would happen to the kernel), but cause the system call to fail with the UNIX variable errno set to 14 (EFAULT). It seems likely that the program is at fault, but there is also a good possibility that a library routine made unwarranted assumptions about word size and pointer size. When the buffer passed to the read() system call is situated (completely or partially) in unallocated memory (beyond HP) or begins in the global data area and ends in the heap, the appropriate warning is given. The buffer is not written. The first two are equivalent to the READ-errors above. Writing out a buffer usually makes no sense when the contents are undefined, so one of the latter two warnings will be generated in this case. A global buffer resides in the data partition; a local buffer resides in the stack partition. This corresponds to global and local variables in a C-program. In the first two cases the WRITE is not performed, in the latter two cases it is.

Traps and signals The sigtrp() monitor call allows sig_no arguments in the range [1..17] (UNIX Version 7 signals); the actual argument is out of range. The signal is one that can only be caused synchronously by the running program on UNIX; it cannot occur to an interpreted program. The sigtrp() monitor call allows trap_no arguments between 0 and 252, and the special values -2 and -3; the actual argument is not one of these. The maximum sizes of the heap and the stack can be limited by options on the command line. If overflow occurs due to such limitations, the corresponding trap is taken, preceded by one of the above warnings. If the memory of the interpreter itself is exhausted, a fatal error follows.

Run-time type checking In general, a type violation has taken place when one of these warnings is given. The float- and instruction pointer warnings are rare and will usually be easy traceable. Integer/character expected will normally occur when unsigned arithmetic is performed on datapointers or when memory containing objects other than integers is copied bytewise. Often, this warning is followed by a warning datapointer expected. This is due to our decision of transforming pointers to (unsigned) integers after doing unsigned arithmetic on them. When such a transformed integer is dereferenced (as if it were a pointer) or, in general, when it is treated as a pointer, this results in a warning. The present library implementation of malloc() causes such a sequence of errors.

These messages are always followed by a tentative description of what is found in memory at the offending place. If the contents of the area was undefined, check the source code for an uninitialized variable of the mentioned type. Officially, the use of an undefined value should result in a EIUND or EFUND trap but the occurrence is so common that a warning is more appropriate. The contents of memory are described as mixed if the data consists of pieces of different types. This happens, e.g., when caller and callee do not agree on the types and lengths of the parameters.

Protection
The program stores a value in Read-Only Memory; the only ROM in the present implementation is the area near location 0. The warning probably results from storing under a NULL pointer. This is only a warning, the store operation is executed normally. Reads from location 0 are not detected. The Return Status Block is the stack area containing the return address, the dynamic link, etc. This may or may not be an error. The current implementation of setjmp()/longjmp() may be responsible for it. If the program does not use setjmp(), there is something very wrong (e.g. argument for ASP too large). Note that there are some library routines (such as alarm()) which use setjmp(). The logical operations AND, XOR, IOR, COM and the compare operation CMS do their jobs bytewise. If one of the bytes is found to be undefined, the corresponding warning is given, and the operation is stopped immediately. The stack is adjusted so interpretation may continue.
It is hard to say what went wrong. Possibly, the argument of the instruction at hand (which indicates the size of the objects to be compared), was too large.

Bad operands Shift instructions yield undefined results if the shift distance is negative or larger than the object size. When doing pointer arithmetic (ADP, ADS), the operand and result pointer must be in the same segment (see sec. 4). E.g. loading the address of the first local and adding 20 to it will certainly give this warning. Pointers may be subtracted only if they point into the same segment. By definition it is illegal to do arithmetic with null pointers. Integers with the size of a pointer and the value zero are recognized as NULL pointers. A well-known C-trick to compute the offset of some field in a struct is converting the null-pointer to the type of the struct and simply taking the address of the field. This trick will -when translated and interpreted- generate this warning because it results in arithmetic with the NULL pointer.

Return area This warning is generated when the size of the expected return value is not equal to the size actually returned.
An interpreted program may have fallen through the end of the code without explicitly doing an exit() or return(). The start-up routine (crt0()) however always expects to get some value returned by the program proper.
Another (less probable) possibility of course is that the code contains a subroutine or function call that does not return properly (e.g. it returns a short instead of a long). This warning will be generated, when the contents of the FRA are fetched after some instruction is executed which can mess up the area. Compiler-generated loadfiles should not generate this message.

Return Status Block The RET instruction found a garbled Return Status Block, or on that resulted from a trap. The RTT (Return from Trap) instruction found a Return Status block that was not created properly by a trap. According to the EM Manual (4.2), "the value of SP just after the return value has been popped must be the same as the value of SP just before executing the first instruction of the invocation." If the Stack Pointer is too large, some dynamically allocated item or some temporary result may have been left behind on the stack. If the Stack Pointer is too small, some locals have been unstacked. Since the interpreter has enough information in the Return Status Block, it recovers correctly from these errors.

Traps

Some traps have ambiguous or non-obvious causes. As far as possible, these are preceded by a warning, explaining the circumstances of the trap.