[comp.std.c] Invalid pointer addresses

davidsen@steinmetz.ge.com (William E. Davidsen Jr) (09/08/88)

  I recently proofread a manual which stated that even calculating the
value of an invalid address could cause a memory fault. I read this to
mean that code like:
	int D_temp[30], 		/* 30 elements */
	    *tempr = D_temp-100;	/* int tempr[100..129] */

would cause a problem even if the pointer were not dereferenced. I would
assume that calculating a value would not EVER cause a dereference (and
thereby a fault), no matter how invalid the address.

  An example in point are the machines which will fault if you try to
dereference a NULL pointer. Simply having the value NULL doesn't cause a
problem. Is there a portion of dpANS which states that this is/isn't
allowed, or that it's implementation dependent? Seems like "common
practice" to me, and portable, as long as you don't use the pointer
other than as a starting point back to the defined array.

BTW: the example above is how you convert a Pascal program with a range
to C. Access is rangechecked by a macro package.

-- 
	bill davidsen		(wedu@ge-crd.arpa)
  {uunet | philabs}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me

gwyn@smoke.ARPA (Doug Gwyn ) (09/08/88)

In article <12088@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes:
>  I recently proofread a manual which stated that even calculating the
>value of an invalid address could cause a memory fault. I read this to
>mean that ...

Yes, that's right.  This problem can occur on segemented architectures
(the 80*86 is not the only one!) and on tagged (or capability-based)
architectures.

>  An example in point are the machines which will fault if you try to
>dereference a NULL pointer. Simply having the value NULL doesn't cause a
>problem. Is there a portion of dpANS which states that this is/isn't
>allowed, or that it's implementation dependent?

A null pointer (which is written as 0 or (some_type *)0, depending on
context, also sometimes as NULL for convenience) is part of the C
language according to the dpANS.  Dereferencing it leads to undefined
behavior.  Computing a pointer to a nonexistent object (other than
just past the end of an array) is also undefined behavior.  [This is
from memory; certainly the dpANS does not promise that it will work
for all conforming implementations.]

>Seems like "common practice" to me,

Lots of nonportable constructs are commonly encountered.

> and portable, ...

No, sorry.  It happens to work (accidentally) in many cases on many
implementations, but since it can fail on some and is not guaranteed,
it is not "portable".

apratt@atari.UUCP (Allan Pratt) (09/09/88)

In article <12088@steinmetz.ge.com> davidsen@crdos1.UUCP 
(bill davidsen) writes:
> 
>   I recently proofread a manual which stated that even calculating the
> value of an invalid address could cause a memory fault.

I suppose that a word-addressing machine could cause a memory fault when
you try to put an odd address in an address register:

	register int *bar = (int *)1;	/* address fault */

============================================
Opinions expressed above do not necessarily	-- Allan Pratt, Atari Corp.
reflect those of Atari Corp. or anyone else.	  ...ames!atari!apratt

henry@utzoo.uucp (Henry Spencer) (09/09/88)

In article <12088@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes:
>  I recently proofread a manual which stated that even calculating the
>value of an invalid address could cause a memory fault...

This is correct.  On single-linear-address-space machines, computing an
invalid address just generates a meaningless number.  On machines with
segments, an address is a structured object:  if the address you start
with is <segment 456, offset 10> and you try to subtract 20 from it,
this may be considered a meaningless and illegal operation -- a kind of
underflow -- rather than a legal operation generating meaningless results.
It depends on whether the designers were segment purists or not, and on
precisely how they defined the format of an address and the semantics
of arithmetic on it.

>... Is there a portion of dpANS which states that this is/isn't
>allowed, or that it's implementation dependent? ...

If you study the section on pointer arithmetic, you will find that, with
the single exception of a pointer one past the end of an array (not its
beginning!), *any* pointer arithmetic which takes you out of the array
you started in is allowed to send you off into the twilight zone.

Analogies to NULL are invalid; NULL is a special case of a legal pointer
which you are not allowed to dereference.
-- 
Intel CPUs are not defective,  |     Henry Spencer at U of Toronto Zoology
they just act that way.        | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

daveb@geac.UUCP (David Collier-Brown) (09/12/88)

In article <12088@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes:
|   I recently proofread a manual which stated that even calculating the
| value of an invalid address could cause a memory fault...
 
From article <1988Sep9.164419.12461@utzoo.uucp>, by henry@utzoo.uucp (Henry Spencer):
|  This is correct.  On single-linear-address-space machines, computing an
|  invalid address just generates a meaningless number.   [...]
|  It depends on whether the designers were segment purists or not, and on
|  precisely how they defined the format of an address and the semantics
|  of arithmetic on it.

Minor point: if you underflow one one linear-address-space machine,
you get the "impossible" (too high) address error. 

-dave (manufacturer unnamed to protect the guilty) c-b 
-- 
 David Collier-Brown.  | yunexus!lethe!dave
 78 Hillcrest Ave,.    | He's so smart he's dumb.
 Willowdale, Ontario.  |        --Joyce C-B

atbowler@watmath.waterloo.edu (Alan T. Bowler [SDG]) (09/30/88)

In article <12088@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes:
>
>  I recently proofread a manual which stated that even calculating the
>value of an invalid address could cause a memory fault. I read this to
>mean that code like:
>	int D_temp[30], 		/* 30 elements */
>	    *tempr = D_temp-100;	/* int tempr[100..129] */
>
>would cause a problem even if the pointer were not dereferenced. I would
>assume that calculating a value would not EVER cause a dereference (and
>thereby a fault), no matter how invalid the address.
>
The problem occurs on those smart architectures that validate a pointer
when it is loaded into a pointer type register, or the contents of
such a register is changed.  In your example assume that you coded
     x = tempr[i];
You really want the compiler to generate 
     lptr PR,tempr       Load pointer register PR
     ldx  IX,i           Load index register IX
     ldr  AC,[IX,PR]     Load data register AC, using PR indexed by IX
     sldr AC,x           Store data register AC into X

If the machine does check the register on the load pointer this could
well fault.  If the compiler is required to accept a sequence like you
want then it will be forced to do the address calculation itself with
the data registers and manufacture a pointer before it actually tries
to do a data fetch.  Since data registers on these architectures are
often smaller than the pointer registers, this tends to be a painfully
slow proceedure.  So you can understand the compiler writer deciding
to assume that he will only be given programs that are written in the
style the machine was designed for and generating the faster sequence.
Often the fast method of doing arithmetic on a pointer involves
some form of "compute effective address into pointer register".
That way the implementor will not continually be complained at, "that
the same program written in Pascal runs 'so much faster' than in C".
This does not stop you from writing your code sequence.  You just must be
aware that there are some machines out there that will not run that
particular program.
   Note that nothing in the above says anything about NULL, since
it never actually gets used where the compiler must do an address
computation.