Is it possible to use an out-of-range index with a smaller array that is preempted from a sufficiently large array?

In my day job, I came across a lot of C codes that resemble the following pattern. I am worried if this pattern is safe.

typedef struct
{
    unsigned char someField : 4;
    unsigned char someOtherField : 4;
    unsigned char body[1];
} __attribute__((__packed__, aligned(1))) SomeStruct;

int main()
{
    unsigned char pack[16] = {};
    SomeStruct* structPack = (SomeStruct*)pack;

    structPack->someField = 0xC;
    structPack->body[4] = 0x5;

    return 0;
}

      

My concern is that the program is using structPack->body[4]

which is still part of a 16 byte array, but is out of scope if we look at the definition SomeStruct

. So there are two ways to look at this:

  • It refers to a valid memory location. There is no danger.
  • It's out of band, so the behavior is undefined.

So my questions are:

  • According to the C standard (more specifically, C89), is this pattern safe or undefined behavior?
  • Also, is it safe for some specific compilers (like GCC) or platform?
  • Are there any better alternatives?

Please note that this kind of code mostly runs on microcontrollers and sometimes runs as an application on the Linux desktop.

+3


source to share


1 answer


Accessing an object with an incompatible lvalue is undefined behavior. Alignment can be resolved by your attribute line, but using a pointer to access the object still breaks strict alias:

unsigned char pack[16] = {};
SomeStruct* structPack = (SomeStruct*)pack;

      

6.5. p7:

The object must have a stored value that can only be accessed by an lvalue expression that is one of the following types:

- a type compatible with the effective type of the object,

- a qualified version of the type, compatible with the effective type of the object,

- a type that is a signed or unsigned type corresponding to the effective type of the object,

- a type that is a signed or unsigned type corresponding to the qualified version of the effective object type,

- a collection or type of union that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregation or union), or

- the type of symbol.

Where is the effective type:

The effective type of an object to access its stored value is the declared type of the object, if any.



SomeStruct*

not compatible with char array.

The correct way to allocate SomeStruct is to use memory allocators or alloca (which will allocate the stack if it is a concern) if the feature is supported.

However, there is the problem of a member body

that is an array of size one, and the Standard does not allow access to it out of bounds (ie body [1]). c99 introduced a solution which is a flexible array element:

typedef struct
{
    unsigned char someField : 4;
    unsigned char someOtherField : 4;
    unsigned char body[];    //must be last
}...

      

When you set the size to highlight this structure, you add extra size depending on how large the member needs to be body[]

.

+3


source







All Articles