home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / lang / c / 11825 < prev    next >
Encoding:
Text File  |  1992-07-31  |  9.4 KB  |  215 lines

  1. Xref: sparky comp.lang.c:11825 comp.std.c:2402
  2. Newsgroups: comp.lang.c,comp.std.c
  3. Path: sparky!uunet!usc!sdd.hp.com!think.com!snorkelwacker.mit.edu!bloom-picayune.mit.edu!news
  4. From: scs@adam.mit.edu (Steve Summit)
  5. Subject: Re: Pointers to freed memory
  6. Message-ID: <1992Jul31.193143.26743@athena.mit.edu>
  7. Summary: yes, Virginia, they could be invalid
  8. Sender: news@athena.mit.edu (News system)
  9. Nntp-Posting-Host: adam.mit.edu
  10. Organization: none, at the moment
  11. References: <1992Jul30.164035.7349@taumet.com> <1992Jul31.035905.20683@oracle.us.oracle.com>
  12. Date: Fri, 31 Jul 1992 19:31:43 GMT
  13. Lines: 200
  14.  
  15. In article <1992Jul31.035905.20683@oracle.us.oracle.com>, wkaufman@us.oracle.com (William Kaufman) writes:
  16. >     Sorry to post asking for random machine specifics, but this one
  17. > intrigued me.  If what Steve says is true, there's a whole lot of busted
  18. > code out there,...some of it with my name on it,...
  19.  
  20. I was going to stay out of this, because Steve Clamage had
  21. already posted the correct answer, but in this case it may help
  22. to have several people saying the same thing.
  23.  
  24. This question, even more than the related one about using funny
  25. pointers to simulate non-zero-based arrays, unfortunately demands
  26. a certain amount of faith.  (I say "unfortunately" because ours
  27. ought to be an extremely rational, deterministic, unambiguous
  28. "science," disdainful of emotional belief systems.)
  29.  
  30. The code
  31.  
  32.     char *p, *anotherp;
  33.     p = malloc(10);
  34.     free(p);
  35.     anotherp = p;
  36.  
  37. really, truly could fail on the last line, due to the
  38. manipulation (via assignment) of an invalid pointer value.
  39. This has been hashed out a number of times on comp.lang.c and
  40. comp.std.c; the conclusion has always been that the Standard
  41. does, strictly speaking, permit the above code to fail.  (The
  42. question is almost worthy of the FAQ list, except that it is not
  43. quite frequent enough, and is way too obscure.)  The clearest
  44. statement of this (admittedly surprising) result is in the
  45. Rationale, section 3.2.2.3, pp. 37-8:
  46.  
  47.     Implicit in the Standard is the notion of invalid
  48.     pointers.  In discussing pointers, the Standard typically
  49.     refers to "a pointer to an object" or "a pointer to a
  50.     function" or "a null pointer."  A special case in address
  51.     arithmetic allows for a pointer to just past the end of
  52.     the array.  Any other pointer is invalid.
  53.  
  54.     An invalid pointer might be created in several ways.  An
  55.     arbitrary value can be assigned (via a cast) to a pointer
  56.     variable.  (This could even create a valid pointer,
  57.     depending on the value.)  A pointer to an object becomes
  58.     invalid if the memory containing the object is
  59.     deallocated.  Pointer arithmetic can produce pointers
  60.     outside the range of an array.
  61.  
  62.     Regardless of how an invalid pointer is created, any use
  63.     of it yields undefined behavior.  Even assignment,
  64.     comparison with a null pointer constant, or comparison
  65.     with itself, might on some systems result in an exception.
  66.  
  67. Now, as I had occasion to remark yesterday, "[The] Rationale is
  68. not part of American National Standard X3.159-1989, but is
  69. included for information only."  I confess that I can find
  70. precious little explicit language in the Standard proper to
  71. support the claim under consideration; indeed, the Rationale
  72. characterizes the notion of invalid pointers as "implicit."
  73. (In fact, other parts of the Standard might lead us to believe
  74. that invalid pointers cause problems only when dereferenced; for
  75. instance, section 3.3.6, p. 48, lines 24-27 state, with respect
  76. to additive pointer arithmetic, that
  77.  
  78.     Unless both the pointer operand and the result point to
  79.     elements of the same array object, or the pointer operand
  80.     points one past the last element of an array object and
  81.     the result points to an element of the same array object,
  82.     the behavior is undefined if the result is used as an
  83.     operand of the unary * operator.
  84.  
  85. , suggesting that we'd be okay as long as we didn't dereference.)
  86.  
  87. If anyone can point to any explicit language elsewhere in the
  88. Standard which pertains to the subject at hand, I'm sure we'd all
  89. we glad to hear it.  (Sections 3.1.2.5, 3.2.2.3, and 3.3.16.1 are
  90. all curiously silent on the allowable values of the pointers
  91. being discussed.)  I do note (as did Steve Clamage) that section
  92. 4.10.3 states (with respect to malloc/free) that "The value of a
  93. pointer that refers to freed space is indeterminate," which says
  94. something.
  95.  
  96. Now, let me hasten to add that it is generally agreed that very
  97. few implementations are likely to make use of the license the
  98. Standard gives them to mistreat programmers who mistreat invalid
  99. pointers.  As Bill points out, "there's a whole lot of busted
  100. code out there."  Academic considerations aside, compiler writers
  101. typically let programmers get away with various unquestionably
  102. bogus and illegal practices, so they're certainly likely to let
  103. them get away with something this obscure.
  104.  
  105. Continuing with Bill's article,
  106. > In article <1992Jul30.164035.7349@taumet.com> steve@taumet.com (Steve Clamage) writes:
  107. >] The C Standard states that the value of the pointer after a call to free
  108. >] is 'indeterminate'.  This means that just reading the value might
  109. >] produce a runtime fault.
  110. >     Well, OK, the pointer will be useless, but will it really be
  111. > dangerous?  What he's got is essentially:
  112. >         struct something *p = (struct something *)rand();
  113. > Could this assignment really cause a fault?  Even if p is never
  114. > dereferenced?  I know this is an improper question, but what machines is
  115. > this true for?
  116.  
  117. The situation is certainly discomforting, especially for those of
  118. us who are conditioned to think about pointers as "addresses," on
  119. a flat-address machine, to boot.  If, however, we confine our
  120. model of pointers to be "magic" objects which, well, point to
  121. things, we will be thinking more along the lines which the
  122. Standard does, and we will be more appreciative of the machine
  123. architectures which do not use flat addressing and which are more
  124. likely to make use of these peculiar freedoms with respect to
  125. pointer manipulation which the Standard gives them.  (For this
  126. reason, I have lately been striving to avoid resorting to words
  127. like "address" when explaining the concept of C pointers.)
  128.  
  129. Let me illustrate with a slightly different example.  Suppose we
  130. have
  131.  
  132.     union    {
  133.         char *p;
  134.         int ia[sizeof(char *) / sizeof(int)];
  135.         } u;
  136.  
  137.     for(i = 0; i < sizeof(char *) / sizeof(int); i++)
  138.         u.ia[i] = rand();
  139.  
  140.     char *anotherp = u.p;
  141.  
  142. This code uses a union to fill in the bits of a pointer with
  143. random values.  (The array and loop allow for the possibility
  144. that sizeof(char *) is greater than sizeof(int), although it
  145. wouldn't work if pointers were somehow smaller than ints.)
  146. This code is quite similar to Bill's
  147.  
  148.     struct something *p = (struct something *)rand();
  149.  
  150. , and it could fail, for the same reason.  We are all fairly
  151. surprised that it could fail (or we were, the first time we heard
  152. about it).
  153.  
  154. However, let's change it just a little bit:
  155.  
  156.     union    {
  157.         double d;
  158.         int ia[sizeof(double) / sizeof(int)];
  159.         } u;
  160.  
  161.     for(i = 0; i < sizeof(double) / sizeof(int); i++)
  162.         u.ia[i] = rand();
  163.  
  164.     double anotherd = u.d;
  165.  
  166. Here we stuff random values into the bits of a double.  I've
  167. worked on machines where simple assignment of garbage floating-
  168. point values resulted in a floating point exception (you may
  169. have, too -- it's a likely occurrence if the machine sets
  170. condition codes after moves as well as after tests and arithmetic
  171. operations), so it wouldn't surprise me at all if the above code
  172. were to fail.  Floating-point values are special -- the bits have
  173. meaning, and some bit patterns are meaningless, so the machine is
  174. allowed to hiccup, burp, and/or vomit when a meaningless pattern
  175. is encountered.  The situation is no different for pointers.
  176. (It's no coincidence that it's floating point values and pointers
  177. which calloc() isn't guaranteed to initialize an array of to 0.)
  178.  
  179. Finally, getting back to the question of which specific machines
  180. might actually disallow the code fragments being discussed, the
  181. Intel 80[234]86 family is often suggested as a "modern" segmented
  182. architecture which treats pointers specially (i.e. not as
  183. arbitrary bit values) and which could, in its protected modes,
  184. conceivably generate faults for things like invalid segment or
  185. selector values (i.e. when the invalid values are loaded at all,
  186. not just when they're dereferenced).  The fact that teeming
  187. millions of programmers are using these processors and writing
  188. code which accidentally or deliberately manipulates invalid
  189. pointers without getting any addressing faults can be used to
  190. argue that the concerns are only in the minds of ivory-tower
  191. academicians and crotchety old Multics users.  In actually (so
  192. I've been told; I've never used one) the 80386 definitely could
  193. generate faults for these cases if it wanted to.  However, as is
  194. usually the case with hardware fault detection and protection
  195. issues, the processor's fault detection mechanisms operate at the
  196. operating system's request and with its assistance.  Because of
  197. the widespread prevalence of code which makes questionable or
  198. invalid assumptions, OS'es for Intel chips tend to disable
  199. several of the protection features.
  200.  
  201. I have crossposted this to comp.std.c in case readers there have
  202. additional insight into language in the Standard which supports
  203. the conclusions that freed pointers are invalid and that invalid
  204. pointers may not be manipulated, but *not* to throw open any
  205. question about the validity of these conclusions themselves.
  206. (If you're encountering this issue for the first time, and you're
  207. tempted to post asking "Golly, `free(p); q = p;' is illegal?  I
  208. can't believe it", here's your answer: believe it.)
  209.  
  210.                     Steve Summit
  211.                     scs@adam.mit.edu
  212.