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