[net.unix-wizards] Questions about nil-pointer dereferences

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)