silver (01/14/83)
We are bringing up System III on a machine that traps attempts to indirect through zero pointers. (Writing code that does this is at very least a poor practice and somewhat antisocial...) Anyway, we run into a lot of these in imported code. I understand that most (all?) DEC hardware supports "int *p = 0; i = *p;" by mapping memory to zero so *p returns zero. Questions: 1: Is there any GOOD reason for writing code that exercises this feature? 2: What if I do "int *a = 0, *b = 0; *b = 10; i = *a;"? What is the value of i? Does this mean that assigning indirect through a nil pointer is deadly to the rest of your nil pointer derefs? Any other comments? Please respond to the net if short and and of general interest, else mail me. Thanks! Alan Silverstein (harpo!seismo!hao!csu-cs!silver) HP Fort Collins Colorado
mjb (01/16/83)
I have never seen code that attempts to reference through a zero pointer and expects zero to be returned. By convention a pointer which is zero points to nothing (== NULL) and should not be used until it is assigned. I think this is perfectly reasonable, since any other value would be subject to the vagaries of pointer size, etc., and would be harder to test for. It is certainly *not* reasonable to expect a null pointer to point at anything predictable. mike braca {decvax,vax135}!brunix!mjb
chris.umcp-cs@UDel-Relay (03/05/83)
From: Chris Torek <chris.umcp-cs@UDel-Relay>
Actually, in Vax virtual memory you always have something at 0;
you have the stuff that is in /lib/crt0.o (or /lib/mcrt0.o if you
compiled with -p) but it isn't necessarily zero. However, you
should never trust to *(int *)0 being legal -- it's not on a large
number of machines (e.g. Codatas). This seems to be a common
"berkeleyism" (assuming that *(int *)0 is legal). If you have
a pointer which could be nil, then you should always check it
first, before following it.
if (p == (int *) 0 || *p == 0) {
some code...
}
or something like that.
dbj.rice@Rand-Relay (03/05/83)
From: Dave Johnson <dbj.rice@Rand-Relay> Many programs under Unix at least unknowingly use the fact that using a zero pointer as a "char *" will give you a null string. Although these are many times bugs which nobody has yet found, we have found in bringing up Phoenix under VMS that a large number of programs will break if there is not a null string at 0. The way this works on a VAX is that the entry point for crt0 contains a register save mask which specifies that no registers be saved. Since crt0 gets loaded at address 0, this results in a zero word at address zero, and thus, a null string at 0. In answer to your question: What if I do "int *a = 0, *b = 0; *b = 10; i = *a;"? What is the value of i? Does this mean that assigning indirect through a nil pointer is deadly to the rest of your nil pointer derefs? the result would be a Bus Error, since location zero is part of the text, rather than the data, and is thus write protected (except, of course, under the OMAGIC format where the result in "i" would be 10). I have not found any programs that try to write at address 0, but there certainly are those that rely on reading there. Dave Johnson Rice University
dbj.rice@Rand-Relay (03/17/83)
From: Dave B Johnson <dbj.rice@Rand-Relay> For programs made with "cc" (without running "ld" explicitly), Berkeley 4.1BSD DOES (implicitly) guarantee a zero byte at address 0. The fact that you had problems with this in porting a locally written C program from Unix 4.1 to VMS/Eunice is a bug in Eunice, not a problem with Unix. 4.1BSD crt0.o ALWAYS has a zero register save mask in it and is ALWAYS loaded at address 0 by "cc". Crt0 is written in assembler and has an explicit ".word 0x0000" for a register save mask. In addition, the value of the register save mask in crt0 has no affect on saving registers, since the Unix kernel does not "call" the program, but rather jumps directly into it after the register save mask. Saving the registers is not necessary since there is nowhere to return to abover crt0. In writing our Unix emulator Phoenix, I have been very careful of details like this which cause Unix programs to break. Phoenix will run almost any Unix program under VMS unmodified, even those that depend on undocumented details of the Unix environment such as this. Dave *B* Johnson Dept. of Mathematical Sciences Rice University P.S. Dave *D* Johnson, huh? I like your name...
guy (03/31/83)
I thought VMS mapped page 0 out of your address space, precisely to prohibit dereferencing null pointers? UNIX on our (i.e., CCI's) Power/5 68000 machine puts the kernel in the low half of your address space, and read/write protects it, so you can't dereference a null pointer there; I agree 1000% with this. Code should not dereference NULL pointers. Period. In fact, it wouldn't be too hard to add a new executable image type to UNIX (at least on machines where throwing away page 0 wouldn't be too expensive, such as VAXes) where the text begins at 1024 (which, I believe, the linker can do already) and page 0 is read/write/execute protected. That way, you can catch bad code which tries to dereference null pointers. Guy Harris RLG Corporation {seismo,mcnc,we13}!rlgvax!guy
dmmartindale (04/03/83)
It may be true that there is a "null string" (zero byte) at location zero on the VAX, but that certainly isn't true of the PDP11 nor would I expect it to be on most other machines. Code which has run on a variety of hardware would tend to get such bugs weeded out of it. Can you give some examples of code which does need zero at location zero to work properly. Dave Martindale
guy (04/04/83)
If a program breaks because there isn't a null string at location 0, that program deserves to break. It's *very* easy to generate a null string; "" generally suffices. And it's *very* easy to say: if (p != NULL && whatever(p)) instead of if (whatever(p)) or whatever the erroneous code was doing. It's only two instructions on a VAX.... Several machines (the SUN and the CCI Power/5, both 68000-based, for example) use the lower part of the address space for the kernel, and dereferencing null pointers on those systems causes a fault (as it should!). VMS also maps page 0 out of the address space; I cast my vote either for demand-paged pure executables (or *all* executables) explicitly starting the text at 1024 and setting page 0's permissions to no read, no write, no execute, no way, or adding a new executable type which does this. Guy Harris RLG Corporation {seismo,mcnc,we13}!rlgvax!guy
dlm (04/05/83)
I wish to add my voice to the notion of page 0 being noread,nowrite,noexe. In addition to the very bad practice of dereferencing NULL ( what if it is not a string?), there are many cases where using a NULL pointer to reference a member of a struct will result in a very small but NONZERO address being generated. The page zero protection on VMS has caught many such bugs. Daryl Monge BTL machaids!dlm
mjl (04/05/83)
The C compiler on V7 had (has?) an interesting problem due to referencing thru a NIL pointer. Somewhere in the parsing routines there is a check of a bit in a structure that maintains parser state information. Under some weird condi- tions that I can't remember exactly (I saw this over 2 years ago) a NIL pointer gets passed to the checking routine. As it so happens, the bit being checked is in the correct state because of the particular instructions in crt0.o. However, we changed the runtime startoff routines, the bit changed, and a syntax error was generated where none in fact existed. Needless to say, this was an EXTREMELY hard bug to find (and correct). In fact, we considered relinking the compiler as a separate I+D program with the standard runtime startoff in data space just to get around this problem (desperation can lead you to do strange things). Mike Lutz (ucbvax!allegra!rochester!ritcv!mjl)