chris@mimsy.UUCP (Chris Torek) (09/17/88)
In article <16041@ism780c.isc.com> news@ism780c.isc.com (News system) [really Marv Rubinstein in disguise] writes: >But consider what might have happened had dpANS mandated that the compution >of a pointer to x[-1] be a valid operation. Then machines for which the >mandated behavior is slow would be not used by people interested in high >performance. The net effect could be salubrious for the computer industry >in the long run. Perhaps. I, for one, would find it useful to be Officially Allowed to compute &arr[negative_offset]. I already make use of this (nonportably) in existing code. There is a second pitfall, however. Consider the following (not strictly conforming) code: struct array_descriptor { int low; /* lower bound */ int bound; /* upper bound - lower bound */ int *data; /* pointer to &data[0] */ }; /* * Allocate a new array whose subscripts range from [low..high) */ struct array_descriptor *new_array(int low, int high) { struct array_descriptor *p; int bound, *dp; /* first get a descriptor */ if ((p = (struct array_descriptor *)malloc(sizeof(*p))) == NULL) return (NULL); /* then check for degenerate arrays (no data) */ p->low = low; if ((bound = high - low) <= 0) { p->bound = 0; p->data = NULL; } else { /* allocate data */ if ((dp = (int *)malloc(bound * sizeof(*dp))) == NULL) { free((char *)p); return (NULL); } p->bound = bound; p->data = &dp[-low]; /* virtual zero point */ } return (p); } If the computation `&dp[-low]' does not over- or under-flow, it produces some pointer. If `low' is positive, it produces a pointer that does not point to valid data, but as long as that pointer is used by adding a value in [low..high) before indirecting, things should work out. Now consider the free routine: void free_array(struct array descriptor *p) { if (p->data != NULL) free((char *)(&p->data[p->low])); free((char *)p); } Do you see the hidden assumption here? if (p->data != NULL) but p->data is not a `valid' pointer. Maybe we had best write if (&p->data[p->low] != NULL) but this is no good either (look again at new_array). At least if (p->bound) seems safe. But what *really* happens if, in new_array, &p->data[-low] turns out to `just happen' to equal NULL? The approach I used in my own (nonportable) code was to keep the original pointer around, just in case (and because there was no p->bound available: allocation of data objects is deferred until they are needed). This also `just happens' to keep happy some garbage collecting C runtime systems. The above code, run on such a system, might fail mysteriously after the garbage collector runs---because the data pointer computed by &p->data[-100] is outside the region allocated by malloc. The GC routine would assume it was free, and cheerfully release it for another malloc(). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris