Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Questions about nil-pointer dereferences (the "plague")

7 views
Skip to first unread message

dbj.rice@rand-relay

unread,
Apr 1, 1983, 12:52:08 AM4/1/83
to
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

chris.umcp-cs@udel-relay

unread,
Apr 1, 1983, 12:57:04 AM4/1/83
to
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.

watcgl!dmmartindale

unread,
Apr 2, 1983, 7:12:14 PM4/2/83
to
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

rlgvax!guy

unread,
Apr 2, 1983, 11:04:10 PM4/2/83
to
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

dbj.rice@rand-relay

unread,
Apr 3, 1983, 9:17:48 PM4/3/83
to
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...

rlgvax!guy

unread,
Apr 4, 1983, 10:22:25 PM4/4/83
to
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.

machaids!dlm

unread,
Apr 6, 1983, 2:14:33 AM4/6/83
to
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

ritcv!mjl

unread,
Apr 6, 1983, 11:14:59 PM4/6/83
to
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)

0 new messages