Shao Miller
6/27/2011 9:46:00 PM
On 6/27/2011 16:09, Alexander Bartolich wrote:
> Shao Miller wrote:
>> On 6/27/2011 07:19, James Kuyper wrote:
>>> On 06/27/2011 07:01 AM, Alexander Bartolich wrote:
>>> ...
>>>> pointer, i.e. declare
>>>>
>>>> typedef struct
>>>> {
>>>> A_t meta;
>>>> double centres[1];
>>>> } B_t;
>>>>
>>>> then allocate sufficient memory and access the array "centres" beyond
>>>> its bounds.
>>>
>>> You should note, however, that while this technique works with most
>>> (?all) C compilers, any program that uses it has undefined behavior.
>>
>> Bounds checking as undefined behaviour? Say it ain't so!
>
> Imagine a platform where the address range reachable by index/offset
> registers is smaller than the address range covered by size_t.
>
Where does 'size_t' come into things? Or even 'ptrdiff_t', though you
didn't bring it up.
Are you suggesting that there are values of 'size_t' for which 'malloc'
might return a null pointer value? I can certainly agree to that.
> Exhibit 1: Intel 8086, running in 16-bit mode, memory model "Huge".
> Exhibit 2: The Atmel AVR, a contemporary 8-bit microcontroller.
>
> The compiler can generate much more efficient code if it assumes that
> the array will not be accessed beyond its bounds.
>
Sure. What bothers me is that Standard text including "bounds"[footnote
94] and "not an element of an array"[6.5.6p7] and "array
object"[6.3.2.1p3, 6.5.2.1p2, 6.5.2.1p3, 6.5.2.1p4, 6.5.9p6, etc.] and
"same array object"[6.5.6p8, 6.5.6p9, 6.5.8p5, 6.5.8p6] appear to lead
to some challenges.
If we use "effective type"[6.5p6] to determine if something is or is not
an "array object," that's fine. But then for:
#include <stdlib.h>
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
typedef struct {
int level;
long index;
} A_t;
typedef struct {
A_t meta;
double centres[1];
} B_t;
int main(void) {
void * vp;
char * finder;
B_t * foo;
double (* dbl_arr_ptr)[6];
double * dbl_ptr;
/* Certainly room for a 'double[6]' */
vp = malloc(sizeof *foo + sizeof (double[5]));
assert(vp);
/* Find 'centres' */
finder = vp;
finder += offsetof(B_t, centres);
/* Pretend a 'double[6]' is there */
dbl_arr_ptr = (void *) finder;
/* Establish the effective type */
1[*dbl_arr_ptr] = 3.14159;
/* Pretend we have a 'B_t' at 'vp' */
foo = vp;
/* Point one past 'centres' */
dbl_ptr = foo->centres + 1;
printf("We have: %f\n", *dbl_ptr);
free(foo);
return 0;
}
Does the 'printf' line invoke undefined behaviour? What does 'dbl_ptr'
point to? Is it one past the single-element 'centres' array or is it
the second element of an object with effective type 'double[6]'?