home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / std / c / 2596 < prev    next >
Encoding:
Text File  |  1992-09-09  |  7.5 KB  |  160 lines

  1. Newsgroups: comp.std.c
  2. Path: sparky!uunet!uunet.ca!wildcan!sq!msb
  3. From: msb@sq.sq.com (Mark Brader)
  4. Subject: struct hack, and other out-of-array references
  5. Message-ID: <1992Sep10.014137.16209@sq.sq.com>
  6. Summary: struct hack legal even though int a[5][5];a[1][7]...; illegal
  7. Organization: SoftQuad Inc., Toronto, Canada
  8. References: <9209080014.AA03467@enet-gw.pa.dec.com> <1992Sep09.112101.1139@x.co.uk> <1992Sep07.104932.20060@x.co.uk> <1992Sep8.124655.1498@Urmel.Informatik.RWTH-Aachen.DE>
  9. Date: Thu, 10 Sep 92 01:41:37 GMT
  10. Lines: 148
  11.  
  12.  
  13. [<> = Norman Diamond;  o' = Clive Feather;  ^^ = Stephen R. van den Berg;
  14.  || = Interpretation Ruling;  ## = the standard;  no indent = me.]
  15.  
  16. <>  You can't go past the end of an array object.  But if malloc() or some
  17. <>  other variable has defined the end of the actual array object, then the
  18. <>  + operator can get you that far, regardless of the declared type that
  19. <>  some other array variable had before getting flattened to a pointer.
  20.  
  21. o'  But there is an interpretation that says that, given
  22. o'     int a [5][5];
  23. o'  the access "a [1][6]" is illegal, because it goes past the bounds of the
  24. o'  array "a [1]". In other words, the declared type of the array does
  25. o'  restrict what can happen to a pointer derived from it.
  26.  
  27. Clive is right to the extent that Norman shouldn't have said "or some other
  28. variable".  (Sorry, Norman, I'd forgotten about this myself when I email
  29. you before.)  However, objects returned by malloc() are another matter.
  30.  
  31.  
  32. <>  Is that an actual interpretation ruling ...?
  33.  
  34. o'  RFI 17, item 16.
  35.  
  36. ||  For an array of arrays, the permitted pointer arithmetic in Standard
  37. ||  ##3.3.6 Semantics (page 48, lines 12-40) is to be understood by
  38. ||  interpreting the use of the word "object" as denoting the specific
  39. ||  object determined directly by the pointer's type and value, *not* other
  40. ||  objects related to that one by contiguity. For example, the following
  41. ||  code has undefined behaviour:
  42. ||      int a [4][5];
  43. ||      a [1][7] = 0;  /* undefined */
  44. ||  Some conforming implementations may choose to diagnose an "array bounds
  45. ||  violation", while others may choose to interpret such attempted accesses
  46. ||  successfully with the "obvious" extended semantics.
  47.  
  48. I found this ruling very surprising, but after reviewing the standard,
  49. I decided that it was correct.  The standard defines [] in terms of +
  50. and *, and the relevant text restricting this usage of + (in section 3.3.6,
  51. ANSI numbering, 6.3.6 in ISO) is the following.  In the typical use
  52. of [], of course, "the pointer operand" is the first operand and "the
  53. integral expression" is the second operand of the []:
  54.  
  55. ##  If the pointer operand points to an element of an array object,
  56. ##  and the array is large enough, the result points to an element
  57. ##  offset from the original element such that the difference in the
  58. ##  subscripts of the resulting and original array elements equals
  59. ##  the integral expression.  In other words, if the expression P
  60. ##  points to the i-th element of an array object, the expressions
  61. ##  P+(N) ... and P-(N) (where N has the value n) point to, respectively,
  62. ##  the i+n-th and i-n-th elements of the array object, provided they
  63. ##  exist.
  64.  
  65. There is then text allowing a pointer one place past the last element to
  66. be computed, and then...
  67.  
  68. ##  If both the pointer operand and the result point to elements of the
  69. ##  same array object, or one past the last element of the same array
  70. ##  object, the evaluation shall not produce an overflow; otherwise, the
  71. ##  behavior is undefined.
  72.  
  73. Now, the important thing is that nowhere in the standard is there any
  74. license to treat the object a as an array of 20 ints.  It is an array
  75. of 4 arrays of 5 ints each.  If you write a[1][7], you are calling for
  76. the computation of a[1]+7.  a[1] here decays to a pointer to int, which
  77. points to the first element of the array a[1].  a[1]+7 does not point
  78. to that array.  The fact that we know that it points to a certain element
  79. of the array a[2] is irrelevant; it is undefined behavior to compute this.
  80.  
  81. ^^  ... but:
  82. ^^      int a[5][5]; int*p;
  83. ^^      p=a[1]+5;
  84. ^^      printf("a[2][0]=a[1][6]=%d\n",*++p);
  85. ^^  
  86. ^^  sure seems to be allowed (although not recommended).
  87.  
  88. Even assuming that there is supposed to be a line assigning a value to the
  89. accessed sub-element of a, this code is certainly not recommended, because
  90. its intent is to print "a[2][0]=" followed by the value of a[2][1]!
  91.  
  92. As to whether it's allowed, there seems to be some room for doubt about
  93. that.  The issue, which I think was raised and not resolved some time
  94. back on this newsgroup, is what exactly the phrase "points one past the
  95. last element of the array object" means.  There is of course an obvious
  96. interpretation/implementation where you the pointer value just gets
  97. incremented by the appropriate element size, but it could also be that
  98. the phrase means to signify an *out-of-band* pointer value, which cannot
  99. be dereferenced unless decremented back into the array.
  100.  
  101. It would take an Interpretation Ruling to settle that.  My own interpre-
  102. tation is that Stephen's code is legal.
  103.  
  104.  
  105. o'  This RFT applies to slices of arrays, but, in *my* opinion, it is
  106. o'  extendable to this case:
  107.  
  108. [In case anyone has read this far in the thread and doesn't know, this code
  109. is what the "struct hack" of the subject line refers to.]
  110.  
  111. o'      struct fred { int i; char s [1]; } *f;
  112. o'      char *s;
  113. o'  
  114. o'      /* ... */
  115. o'      f = malloc (sizeof f + strlen (ss));
  116. o'      if (f != NULL)
  117. o'          strcpy (f->s, ss);
  118. o'  
  119. o'  The pointer f->s points to an object with type "char [1]", and so, if
  120. o'  strlen (ss) > 0, the access to (f->s)[1] required by strlen is undefined
  121. o'  according to this RFI, even though the array has already decayed to a
  122. o'  pointer.
  123.  
  124. Clive's opinion here is wrong (see also signature quote).  The difference
  125. between this and the other case is that the standard provides (in ANSI
  126. section 4.10.3, ISO 7.10.3) specific dispensation for the value returned by
  127. malloc() to:
  128.  
  129. ##  ... be assigned to a pointer to any type of object and then used to
  130. ##  access such an object or an array of such objects in the space
  131. ##  allocated ...
  132.  
  133. The pointer f->s does point to an object with type char[1], but it is
  134. also a pointer into the space returned by malloc(), which may be treated
  135. as an array of chars.  That is, when strcpy computes the equivalent of
  136. (f->s)[1], and therefore (f->s)+1, both the pointer operand of +, i.e.
  137. f->s, and the computed result *are* within the same array, namely the one
  138. returned by malloc(), and all is well.
  139.  
  140.  
  141. I would also argue that the Interpretation Ruling cited above would not
  142. apply if the type of the example array "a" had been char instead of int.
  143. The definitions of "object" and "byte" (in ANSI section 1.6, ISO 3.14 and
  144. 3.4) in effect require that it be possible to treat any object as an
  145. array of any character type.  This guarantee is assumed, of course, by
  146. any number of library functions.  Once again, this should render legal any
  147. references that are out of bounds in a subarray but which address locations
  148. known to be in the containing array.
  149.  
  150. If all this had been raised during standardization, I'd've asked for a
  151. change to render a[1][7] legal as well, because I think it's more C-like
  152. for it to be legal, and more consistent with the three exceptions that I've
  153. just mentioned.  But it isn't, even though I think they all are.
  154. -- 
  155. Mark Brader            "'A matter of opinion'[?]  I have to say you are
  156. SoftQuad Inc., Toronto          right.  There['s] your opinion, which is wrong,
  157. utzoo!sq!msb, msb@sq.com      and mine, which is right."  -- Gene Ward Smith
  158.  
  159. This article is in the public domain.
  160.