Xref: utzoo comp.std.c:1905 comp.lang.c:23103 Path: utzoo!attcan!uunet!mstan!amull From: amull@Morgan.COM (Andrew P. Mullhaupt) Newsgroups: comp.std.c,comp.lang.c Subject: Re: commom malloc/free practice breaks standard - author strikes back Summary: Chapter and verse (from one source) Message-ID: <458@e-street.Morgan.COM> Date: 21 Oct 89 01:04:44 GMT References: <1989Oct16.111059.3840@anucsd.oz> <992@cirrusl.UUCP> Organization: Morgan Stanley & Co. NY, NY Lines: 107 In article <992@cirrusl.UUCP>, dhesi@sun505.UUCP (Rahul Dhesi) writes: > > I, like many others, rely on the gurus in comp.lang.c for much valuable > information. Can somebody quote chapter and verse to show that the > standard does require the series of casts > > void * -> OBJ * -> void * > > to yield the original pointer? > The short answer seems to be that the standard does not always require this; and the long answer follows: (If you don't want to read the long answer; now's the time ...) Well, in one commonly available source, "C: A Reference Manual" by S. P. Hardison and G. L. Steele, Jr., (1987, 1984) we find: page 115.: "Draft Proposed ANSI C introduces the type 'void *', or pointer to void, to represent a 'universal' data pointer." and then page 268.: "All other pointer types (except perhaps function pointers) can be converted to type void * and back without change;" Which answers the closely related question; that the cast sequence OBJ * -> void * -> OBJ * must not change the pointer to OBJ. In particular, if the pointer to type void in question is the result of a cast OBJ * -> void * then the subsequent cast sequence void * -> OBJ * -> void * cannot change the value of the pointer to type void; via the apparent theorem: {OBJ * -> void * -> OBJ *} -> void * == {OBJ *} -> void * where == indicates that the two cast sequences arrive at the same pointer to void by replacement of the equivalent cast sequences in braces. (The braces are not indicative of C syntax, along with the -> symbol for typecasting.) Now on page 126.: "In general, if the alignment requirement for a type S is at least as stringent for a type D, (...) then converting a 'pointer to type S' to a 'pointer to type D' is safe. 'Safe' here means that the resulting pointer to type D will work as expected if used to fetch or store an object of type D, and that a subsequent conversion back to the original pointer type will recover the original pointer. A corollary to this is that any data pointer can be converted to type char * and back safely." It seems that the intent of the proposed standard is that the alignment requirement for type void is no more stringent than that of any other type. (This would seem to make sense, since you shouldn't have to align something you do not ever actually intend to store - an object of type void.) Further on page 126.: "If the alignment requirement for a type S is less stringent than that for type D, then the conversion from a 'pointer to type S' to a 'pointer to type D' could result in either of two kinds of unexpected behavior. First, an attempt to use the resulting pointer to fetch or store an object of type D may cause an error, halting the program. Second, the hardware or implementation may 'adjust' the destination pointer to be legal, usually by forcing it back to the nearest previous legal address. A subsequent conversion back to the original pointer type may not recover the original pointer." It is entirely clear if you accept that void is no more stringent than any other type, then types not of this minimal stringency are not guaranteed to survive the cast sequence in question unless a precondition essentially that the pointer to void is a legitimate pointer to OBJ before the casting begins. One should expect that if such a precondition is false, that the desired cast sequence is not only unguaranteed by the Proposed Draft ANSI Standard, but likely to be unpleasant at run-time; i.e. a bug. One often has occasion to cast a pointer to void which is the result of one of the alloc family of functions. These return pointers which are guaranteed to satisfy even the most stringent alignment requirements, (Harbison & Steele page 345.) One can think of this as being the same as if the pointer to the desired type was assigned by the allocation function, and then cast to void * where by the above theorem it can be safely cast to and from void *. I can't find the answer to an even more obscure question arising from this line of inquiry: It seems that the sometime guarantee of the theorem above is false in the case that the type OBJ * is defined in a typedef with the volatile type specifier. (I.e. I can't seem to eliminate the scary possibility of a volatile pointer!) The "obvious" trick is illegal; consider: typedef OBJ *ptr; /* ptr is type 'pointer to OBJ' */ typedef volatile ptr BLUNGE; /* BLUNGE is the volatile kind */ This is explicitly forbidden by Draft Proposed ANSI C, "Typedef names should not be mixed with other type specifiers" (Harbison & Steele page 116.) I haven't had enough experience chasing the lexical rules and syntax to ensure that no other way to declare a volatile pointer type exists; but I hope it's impossible. Ominously, we have been able to get gcc to accept the declaration char * volatile p; but I don't know what it really is or means. Later, Andrew Mullhaupt