home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.lang.c
- Path: sparky!uunet!gatech!hubcap!mjs
- From: mjs@hubcap.clemson.edu (M. J. Saltzman)
- Subject: Re: Pointers outside of array boundary
- Message-ID: <1992Jul29.183819.3662@hubcap.clemson.edu>
- Summary: Thanks and summary
- Organization: Clemson University, Clemson SC
- References: <1992Jul28.180945.22332@hubcap.clemson.edu>
- Date: Wed, 29 Jul 1992 18:38:19 GMT
- Lines: 99
-
- Thanks to everyone who responded to my query about 1-based array indexing.
- Below is a summary of replies. The upshot is that there *is* a machine
- on which this code fails.
-
- In article <1992Jul28.180945.22332@hubcap.clemson.edu> I wrote:
- >I am having an e-mail conversation with someone regarding the
- >_Numerical_Recipes_in_C_ practice of creating arrays with offset
- >indices. The sample code in question is
- >
- > float x = malloc(10*sizeof(float));
- ^
- > --x;
-
- Should have been *x, of course (but it wasn't my code 8^)).
-
- >which is supposed to give an array whose elements are addressed
- >as x[1]..x[10].
- >[...]
- > What could possibly go wrong if we only ever dereference
- >x[1]..x[10]?
- >[...]
- >My question is: Can anyone name an existing machine on which this code
- >could fail, or give a really convincing hypothetical argument why it
- >is a bad idea?
- >[...]
- >
- >Also, could someone quote the relevant part of the standard?
- >[...]
-
- Mark Brader (msb@sq.com) quoted the standard, and the rationale:
-
- }It's in section 3.3.6 (ANSI numbering, 6.3.6 in ISO numbering), which
- }defines the operators + and -. (The statement could have been written
- }as x = x - 1; and this would be equivalent; I won't trouble to cite the
- }parts of the standard that specify this equivalence.) Here's the sentence:
- }
- }# If both the pointer operand and the result point to elements of
- }# the same array object, or one past the last element of the array
- }# object, the evaluation shall not produce an overflow, otherwise
- }# the behavior is undefined.
- }
- }"Undefined behavior" allows the program to abort, or worse.
-
- And:
-
- } The "one past the end of the array" rule wasn't in K&R, but people
- }were in the habit of using it. The Rationale says:
- }
- }| An important endorsement of widespread practice is the requirement
- }| that a pointer can always be incremented to _just_past_ the end of
- }| an array, with no fear of overflow or wraparound:
- }|
- }| SOMETYPE array[SPAN];
- }| /* ... */
- }| for (p = &array[0]; p < &array[SPAN]; p++)
- }|
- }| This stipulation merely requires that every object be followed by one
- }| byte whose address is representable. That byte can be the first byte
- }| of the next object declared[,] for all but the last object located in
- }| a contiguous segment of memory. (In the example, the address &array[SPAN]
- }| must address a byte following the highest element of array.) Since the
- }| pointer expression p+1 need not (and should not) be dereferenced, it is
- }| unnecessary to leave room for a complete object of size sizeof(*p).
- }|
- }| In the case of p-1, on the other hand, an entire object _would_ have
- }| to be allocated prior to the array of objects that p traverses, so
- }| decrement loops that run off the bottom of an array may fail. This
- }| restriction allows segmented architectures, for instance, to place
- }| objects at the start of a range of addressable memory.
- }
- }They are tacitly assuming here that a pointer to a multi-byte object
- }is implemented using a pointer to the first byte. While the standard
- }does not actually require this, it is common practice. Since the Rationale
- }is only suggesting a convenient implementation, that's all right.
-
- Most people suggested hypothetical architectures on which performing
- the decrement operation could result in a trap, due to either
- underflow on an offset pointer or hardware-implemented range checking.
- But Barry Gorman (GORMAN_B@prime1.lancashire-poly.ac.uk) reports:
-
- }I have tried your code (slightly extended) on a Pr1me '50 series.
- }This machine has a 'segmented' architecture, where a pointer has a segment
- }field and an offset field (plus a bit more). If malloc() serves up a pointer
- }with a zero offset (it does if you grab a full segment) then decrementing
- }it causes the offset to go to 0xFFFE, and decrements the segment field.
- }When you use an index such as x[2], only the offset field gets incremented,
- }and the segment field is one short, i.e. it uses the WRONG segment.
-
- So this is a case where the decrement and increment operators don't
- behave as inverses, i.e. for float *x, x != --x + 1. This seems to me
- to be much more insidious than trapping the decrement operator.
-
- Anyhow, I think that clears the matter up pretty completely. Thanks
- again to everyone who repiled.
-
- --
- Matthew Saltzman
- Clemson University Math Sciences
- mjs@clemson.edu
-