[comp.lang.c] Creating pointer with all bits 0

msb@sq.sq.com (Mark Brader) (08/31/89)

> > could you not access memory location 0 by writing:
> >	p = 0;  /* integer variable that happens to be set to zero */
> >	data = *(int *)p;  /* no constant expression in this line */

> Probably, but there's nothing to stop a cast doing something strange.
> This may work better (but of course is still completely unreliable):
>    union {int i; int *p} x;
>    x.i = 0;
>    data = *x.p;

Int indeed.  However, this is suggestive.  You could do:

   union {char c [sizeof (int *)]; int *p;} x;
   int i;
   for (i = 0; i < sizeof x.c; ++i) x.c[i] = 0;
   data = *x.p;

On the other hand, it's simpler to use memset():

      int *p;
      memset ((void *) p, 0, sizeof p);
      data = *p;

Or bzero() if you have that and not memset(), or for that matter
there's the trickier but more universally available way:

      strncpy ((char *) p, "", sizeof p);

It may as well be repeated for anyone who's coming in late that
the point here is to get a pointer p with all bits zero, for use
on a machine where null pointers have some other pattern of
bits and all-bits-zero is a meaningful pointer.  It may as well
also be repeated that the bit pattern (or patterns; they could
depend on the type) of null pointers have nothing to do with the
fact that 0 is a correct way to write a null pointer constant.

-- 
Mark Brader, SoftQuad Inc., Toronto, utzoo!sq!msb, msb@sq.com
#define	MSB(type)	(~(((unsigned type)-1)>>1))

This article is in the public domain.

cpcahil@virtech.UUCP (Conor P. Cahill) (08/31/89)

In article <1989Aug31.052756.18524@sq.sq.com>, msb@sq.sq.com (Mark Brader) writes:
> 
>       int *p;
>       memset ((void *) p, 0, sizeof p);

This would probably drop core on most systems.  You probably want to 
do something like:

       memset ((void *) &p, 0, sizeof p);
                        ^^

> Or bzero() if you have that and not memset(), or for that matter
> there's the trickier but more universally available way:
> 
>       strncpy ((char *) p, "", sizeof p);

Yet again, you need the & on the p.



-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

msb@sq.sq.com (Mark Brader) (09/02/89)

Conor P. Cahill (cpcahil@virtech.UUCP) corrects me:
>        memset ((void *) &p, 0, sizeof p);
>                         ^^

He's right, of course.  I hate it when other people post an incorrect
correction to a posted article, and I apologize for doing that myself.

-- 
Mark Brader, utzoo!sq!msb, msb@sq.com		C unions never strike!

This article is in the public domain.

rns@se-sd.NCR.COM (Rick Schubert ) (09/02/89)

In article <1989Aug31.052756.18524@sq.sq.com> msb@sq.com (Mark Brader) writes:
[Someone suggested:]
 >> > could you not access memory location 0 by writing:
 >> >	p = 0;  /* integer variable that happens to be set to zero */
 >> >	data = *(int *)p;  /* no constant expression in this line */
[To which Mark Brader responded:]
 
 >      int *p;
 >      memset ((void *) p, 0, sizeof p);
 >      data = *p;

 >It may as well be repeated for anyone who's coming in late that
 >the point here is to get a pointer p with all bits zero, for use
 >on a machine where null pointers have some other pattern of
 >bits and all-bits-zero is a meaningful pointer.  It may as well
 >also be repeated that the bit pattern (or patterns; they could
 >depend on the type) of null pointers have nothing to do with the
 >fact that 0 is a correct way to write a null pointer constant.
 
 It may as well also be repeated (or stated, if it was not originally
 stated (peated?)) that the pointer with a bit pattern of all-bits-zero does
 not necessarily reference location 0 (and that the pointer to location 0 is
 not necessarily represented by a bit pattern of all-bits-zero).
 
 -- Rick Schubert (rns@se-sd.sandiego.NCR.COM)

jeffrey@algor2.algorists.com (Jeffrey Kegler) (09/06/89)

In article <2030@se-sd.NCR.COM> rns@se-sd.UUCP (Rick Schubert (AEP)) writes:
>In article <1989Aug31.052756.18524@sq.sq.com> msb@sq.com (Mark Brader) writes:
>[Someone suggested:]
> >> > could you not access memory location 0 by writing:
> >> >	p = 0;  /* integer variable that happens to be set to zero */
> >> >	data = *(int *)p;  /* no constant expression in this line */
>[To which Mark Brader responded:]
> 
> >      int *p;
> >      memset ((void *) p, 0, sizeof p);
> >      data = *p;
>
> >It may as well be repeated for anyone who's coming in late that
> >the point here is to get a pointer p with all bits zero, for use
> >on a machine where null pointers have some other pattern of
> >bits and all-bits-zero is a meaningful pointer. ...

For those who may not know, constant pointers, that is pointers which
are not created by taking an address or created by malloc(), are
required in some types of programming.  UNIX device drivers and
interfaces in any OS to boards which have registers at fixed
addresses, must have constant pointers to addresses whose bit pattern
is dictated by the hardware.  The bit pattern 0x0 of whatever length
might be one of the addresses required.

As far as I can follow the dpANS, any such code requires some trick
whose behavior is implementation-defined or undefined behavior.
That's fine, since any such code is inherently not portable, could
never be strictly conforming, and only makes sense on a given
architecture.  "Undefined behavior" does not mean the implementation
must blow up in your face.  It means the implementation may do
anything that it pleases--blow up in your face or work as you
intended.

Each implementation on an architecture where constant pointers may be
necessary will, in some circumstance where dpANS allows
"implementation defined behavior" or "undefined behavior", allow
access to the appropriate fixed locations.  Which tricks the
implementation will allow and how they work is up to the
implementation.  In Footnote 42 to 3.3.4 dpANS expresses the hope
implementors will use integers cast to pointer as the allowed trick to
accomplish this.  But dpANS seems to allow anything that does not
break a strictly conforming program, so long as the implementation
documents its choice.  Since no strictly conforming program can try
any of these tricks, this is not a major restriction.

Apparently the only difference between allowing implementation defined
behavior and allowing undefined behavior is that documentation of the
former is required, no matter what, while documentation of the latter
is optional.

Question: Is an implementation whose null pointer is the same as the
result of some integer-to-pointer cast conforming?  Apparently not,
since 3.2.2.3 states, "... a null pointer is guaranteed to compare
unequal to a pointer to any object or function."

If I am correct, this could cause problems.  It is not hard to imagine
an implementation where every possible pointer bit pattern is a valid
physical address.  No pattern would remain for the null pointer.  The
implementation would have to carry an extra bit or more with each
pointer, rendering pointer operations much less efficient.

The Classic C solution to this is that the programmer had to know if
what he was testing against the null pointer was a pointer derived
from a fixed address somehow.  If so, and if the bit pattern of the
null pointer (usually all zeros) was a valid fixed address in that
context, the test against the null pointer was useless for determining
if the fixed address pointer was an invalid value.  In practice, this
restriction was no problem.  People who are careless with pointers to
fixed addresses receive little sympathy from any quarter.
-- 

Jeffrey Kegler, Independent UNIX Consultant, Algorists, Inc.
jeffrey@algor2.ALGORISTS.COM or uunet!algor2!jeffrey
1762 Wainwright DR, Reston VA 22090

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/06/89)

In article <1989Sep6.052228.17374@algor2.algorists.com> jeffrey@algor2.UUCP (Jeffrey Kegler) writes:
>If I am correct, this could cause problems.  It is not hard to imagine
>an implementation where every possible pointer bit pattern is a valid
>physical address.  No pattern would remain for the null pointer.

I've already explained how an implementation could provide a null
pointer anyway, by using a datum in the run-time library whose address
would be used for null pointers.

tneff@bfmny0.UUCP (Tom Neff) (09/06/89)

I guess this 0 vs NULL thing will never get settled no matter how many
times Doug and Chris explain it.

So I'll carry the sandbucket for a turn. ;-)

 * Pointer and integer don't have to occupy the same storage or look
alike, and even where they do a NULL pointer doesn't have to contain all
zero bits.

 * Where a conforming program LOOKS like it's violating the above, by
casting 0 to a pointer type to create NULL, the compiler is welcome to
treat that instance of "0" *specially* so as to really create a NULL.
It does NOT mean that the pointer's storage is temporarily treated as
int storage and filled with the bit pattern an int 0 would get.

 * Other integer to pointer casts are not guaranteed to be portable.

 * Environments where constant pointers other than NULL are significant
do occur, but the situations where you use them are non-portable.  ANS
conforming compilers will presumably offer non portable extensions to
cover such things.  In widespread environments like UNIX where this is
an issue, it would be reasonable to defer to POSIX (e.g.) for guidance.
In DOS land and such, just use what the vendor supplies.
-- 
Annex Canada now!  We need the room,	\)	Tom Neff
    and who's going to stop us.		(\	tneff@bfmny0.UU.NET

henry@utzoo.uucp (Henry Spencer) (09/06/89)

In article <1989Sep6.052228.17374@algor2.algorists.com> jeffrey@algor2.UUCP (Jeffrey Kegler) writes:
>Question: Is an implementation whose null pointer is the same as the
>result of some integer-to-pointer cast conforming?  Apparently not,
>since 3.2.2.3 states, "... a null pointer is guaranteed to compare
>unequal to a pointer to any object or function."

Does not follow.  There is nothing that says that the result of casting
an integer to a pointer will be a pointer to an object.  It is entirely
legitimate for some integers to become null pointers when cast.

>If I am correct, this could cause problems.  It is not hard to imagine
>an implementation where every possible pointer bit pattern is a valid
>physical address.  No pattern would remain for the null pointer...

The pdp11, the very first machine on which C was implemented, had this
property.  The solution was to use a software convention in which no
variable was ever put at location 0, and any programmer who *really*
wanted to use something at 0 was breaking the rules and was on his own.
I see no reason why the same approach won't work for ANSI C.
-- 
V7 /bin/mail source: 554 lines.|     Henry Spencer at U of Toronto Zoology
1989 X.400 specs: 2200+ pages. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

flaps@dgp.toronto.edu (Alan J Rosenthal) (09/06/89)

Really, an implementation is free to accept "*(char *)0 = 5;" as an instruction
to set memory location zero to 5.  Dereferencing a null pointer gets undefined
behaviour.  This is a non-problem.


jeffrey@algor2.algorists.com (Jeffrey Kegler) writes:
>Question: Is an implementation whose null pointer is the same as the
>result of some integer-to-pointer cast conforming?  Apparently not,
>since 3.2.2.3 states, "... a null pointer is guaranteed to compare
>unequal to a pointer to any object or function."

I think the contents of a special memory location is not necessarily an
"object" in the pANS sense.  In any case, dereferencing the null pointer
is an implementation-specific way of accessing this memory location, and
need not be construed as a normal pointer dereference (although it would
probably be implemented as such).  For example, the (FILE *)0 argument to
fclose() to close all fps is not a pointer to an object, although if only
one file is open it does refer to an object.

ajr

jeffrey@algor2.algorists.com (Jeffrey Kegler) (09/07/89)

In article <10947@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <1989Sep6.052228.17374@algor2.algorists.com> jeffrey@algor2.UUCP (Jeffrey Kegler) writes:
>>If I am correct, this could cause problems.  It is not hard to imagine
>>an implementation where every possible pointer bit pattern is a valid
>>physical address.  No pattern would remain for the null pointer.
>
>I've already explained how an implementation could provide a null
>pointer anyway, by using a datum in the run-time library whose address
>would be used for null pointers.

Sorry to have missed the original explanation.  I watch for Doug's
postings, but this one of his clarifications slipped by me.

Followup question: Must the dummy datum above be handled in some way
(such as preceding it with another dummy) that guarantees it is not
one past the end of any array?  It makes sense to me that it should,
but the standard does not seem to require this of a conforming
implementation.  The standard guarantees the pointer to an object will
not compare equal to the null pointer (3.2.2.3), but is the pointer
one past the end of the array a pointer to an object?  Not, IMHO, by
the definition of object in 1.6.

The situation where a loop incrementing a pointer through an array
contains a test of that pointer against the null pointer must be
reasonably familiar to Classic C programmers.  (The test against the
null pointer might be to test for uninitialized pointers, or some
error condition might set the pointer to null.)  Must the special case
of the pointer one past the end of the array being compared to the
null pointer be guarded against to be strictly conforming?  Again, yes,
as far as I can discern.

The standard requires that arithmetic with a pointer one past the end
of an array not overflow (3.3.6), and suggests that this be
implemented by there actually being a physical object at that place
(Footnote 43) but does not seem to require such an object.
-- 

Jeffrey Kegler, Independent UNIX Consultant, Algorists, Inc.
jeffrey@algor2.ALGORISTS.COM or uunet!algor2!jeffrey
1762 Wainwright DR, Reston VA 22090

diamond@csl.sony.co.jp (Norman Diamond) (09/08/89)

In article <1989Sep6.052228.17374@algor2.algorists.com> jeffrey@algor2.UUCP (Jeffrey Kegler) writes:

>Question: Is an implementation whose null pointer is the same as the
>result of some integer-to-pointer cast conforming?  Apparently not,
>since 3.2.2.3 states, "... a null pointer is guaranteed to compare
>unequal to a pointer to any object or function."

This looks like a bit of a problem all right.  Can it still be fixed
by editorial change?  For example, "... any legally created object or
function" or "... any C object or function."

--
-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/09/89)

In article <10816@riks.csl.sony.co.jp> diamond@riks. (Norman Diamond) writes:
>In article <1989Sep6.052228.17374@algor2.algorists.com> jeffrey@algor2.UUCP (Jeffrey Kegler) writes:
>>Question: Is an implementation whose null pointer is the same as the
>>result of some integer-to-pointer cast conforming?  Apparently not,
>>since 3.2.2.3 states, "... a null pointer is guaranteed to compare
>>unequal to a pointer to any object or function."

The code is already not strictly conforming, since the requisite cast
is implementation-dependent.

>This looks like a bit of a problem all right.  Can it still be fixed
>by editorial change?  For example, "... any legally created object or
>function" or "... any C object or function."

It's not a problem.  The Standard only talks about objects and functions
in its context; they're technical C-specific terms.

guy@auspex.auspex.com (Guy Harris) (09/10/89)

 >>Question: Is an implementation whose null pointer is the same as the
 >>result of some integer-to-pointer cast conforming?  Apparently not,
 >>since 3.2.2.3 states, "... a null pointer is guaranteed to compare
 >>unequal to a pointer to any object or function."
 >
 >This looks like a bit of a problem all right.  Can it still be fixed
 >by editorial change?  For example, "... any legally created object or
 >function" or "... any C object or function."

Well, it might be fixable in the interpretation phase, since "3.1.2.4
Storage durations of objects" has this to say:

	   An object has a *storage duration* that determines its
	lifetime.  There are two storage durations: static and
	automatic.

	   An object whose identifier is declared with external or
	internal linkage, or with the storage-class specifier "static"
	has *static storage duration*. ...

	   An object whose identifier is declared with no linkage and
	without the storage-class specifier "static" has *automatic
	storage duration*. ...

and "4.10.3 Memory management functions" has this to say:

	...

	   The "calloc" function allocates space for an array of "nmemb"
	objects, each of whose size is "size". ...

	...

	   The "malloc" function allocates space for an object whose
	size is specified by "size" ...

while "3.3.4 Cast operators" says only:

	...

	An arbitrary integer may be converted to a pointer.  The result
	is implementation-defined.

	...

and "3.1.2.5 Types" says:

	...A pointer type describes an object whose value provides a
	reference to an entity of the referenced type. ...

so I see no obvious indication here that the result of converting an
arbitrary integer to a pointer is a pointer whose value refers to an
*object* - it seems only to refer to an "entity".  The only way I see of
getting an object is to define it with static or automatic storage
duration, or call "malloc" or "calloc". 

It's perhaps not ideal that the definition of "object" doesn't
explicitly indicate how you get objects, but I think this may be, as
indicated, repairable in the interpretation phase, if necessary.

jeffrey@algor2.algorists.com (Jeffrey Kegler) (09/10/89)

Guy Harris writes:

> Jeffrey Kegler writes:

> > Question: Is an implementation whose null pointer is the same as the
> > result of some integer-to-pointer cast conforming?  Apparently not,
> > since 3.2.2.3 states, "... a null pointer is guaranteed to compare
> > unequal to a pointer to any object or function."

> Well, it might be fixable in the interpretation phase, since 3.1.2.4
> has this to say ... and 4.10.3 has this to say ... while 3.3.4 says
> only ... and 3.1.2.5 says ...  so I see no obvious indication here
> that the result of converting an arbitrary integer to a pointer is a
> pointer whose value refers to an *object* 

The definition of 1.6 is loose enough that any readable physical
location is an "object".  In fact, the "readable" may not even be a
requirement.

1.6 defines an object as "a region of data storage in the execution
environment, the contents of which can represent values."  Given the
target might be firmware it is clear that the definition has to be
this broad.  There is no reference to declaration or C language in the
definition of "object", nor should there be.

Note this means Doug Gwyn's workaround (having a dummy for the null
pointer to point to, if worst comes to worst) to 3.2.2.3, while it
will achieve the intent of the standard, still violates its exact
wording as quoted above.

> it seems only to refer to an "entity".  The only way I see of
> getting an object is to define it with static or automatic storage
> duration, or call "malloc" or "calloc".

As above, objects can pre-exist, and be accessed with the result of an
integer to pointer cast.  This appears to have been explicitly the
intention (Footnote 42).

> It's perhaps not ideal that the definition of "object" doesn't
> explicitly indicate how you get objects, but I think this may be, as
> indicated, repairable in the interpretation phase, if necessary.

Can sections of the standard be rewritten in the "interpretation
phase"?  It seems this might be what it amounts to.

[ Aside: In this context 3.1.2.4 reads very strangely.  It says every
object has one of two storage durations (static and automatic).  It
goes on to say that the storage duration depends on the declaration,
apparently assuming every object has one, which of course is not the
case. ]
-- 

Jeffrey Kegler, Independent UNIX Consultant, Algorists, Inc.
jeffrey@algor2.ALGORISTS.COM or uunet!algor2!jeffrey
1762 Wainwright DR, Reston VA 22090

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/10/89)

In article <1989Sep10.040055.10651@algor2.algorists.com> jeffrey@algor2.UUCP (Jeffrey Kegler) writes:
>1.6 defines an object as "a region of data storage in the execution
>environment, the contents of which can represent values."
>Note this means Doug Gwyn's workaround (having a dummy for the null
>pointer to point to, if worst comes to worst) to 3.2.2.3, while it
>will achieve the intent of the standard, still violates its exact
>wording as quoted above.

Not really, since a null pointer implemented as a dummy would still
be incapable of having contents.  That's the same reason "void" is
not an object type.  They're both special language elements treated
differently from objects by the compiler.

>Can sections of the standard be rewritten in the "interpretation
>phase"?  It seems this might be what it amounts to.

No; the most that can happen is that X3J11 can issue "information
bulletins" containing guidance for interpreting the Standard;
however, such bulletins are not considered (legally?) part of the
Standard.

>[ Aside: In this context 3.1.2.4 reads very strangely.  It says every
>object has one of two storage durations (static and automatic).  It
>goes on to say that the storage duration depends on the declaration,
>apparently assuming every object has one, which of course is not the
>case. ]

I think it meant "every object tagged with an identifier".  It would
be useful for an official ruling on this interpretation..

richard@aiai.ed.ac.uk (Richard Tobin) (09/11/89)

]]Question: Is an implementation whose null pointer is the same as the
]]result of some integer-to-pointer cast conforming?  Apparently not,
]]since 3.2.2.3 states, "... a null pointer is guaranteed to compare
]]unequal to a pointer to any object or function."
]
]This looks like a bit of a problem all right.  Can it still be fixed
]by editorial change?  For example, "... any legally created object or
]function" or "... any C object or function."

I would have thought the right solution to this was for there to be no
guarantee that the result of an arbitrary integer-to-pointer cast be
an "object or function".  Indeed, I believe this is the case: 3.3.4 says
"An arbitrary integer may be converted to a pointer.  The result is
implementation-defined."

In a "reasonable" implementation, casting a geuine pointer to an integer
and back again will result in the same pointer, so it certainly won't
compare equal to zero.  Casting other integers to pointers should only
be done when you know enough about the machine and compiler you are using.

[Please, no flames about casting pointers to integers.  I know it's not
guaranteed to do anything useful, but it does on all the machines I care
about, and has completely reasonable uses.]

-- Richard
-- 
Richard Tobin,                       JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,           ARPA:  R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.                UUCP:  ...!ukc!ed.ac.uk!R.Tobin