Do pointers to different types match the "common initial sequence" rule?

86 Views Asked by At

If I have a union that contains pointers to different types of data, would it be legal to free malloced memory via a different field than the one it was assigned to? Does it even match the "common initial sequence" rule?

#include <stdlib.h>

typedef struct {
    int type;
    union {
        void *entries;
        long *long_entries;
        // etc
    } u;
} Bar;

int main (void) {
   Bar bar;
   bar.u.long_entries = malloc(6 * sizeof(long));
   free(bar.u.entries);
}

I'm inclined to say that this is legal, but I'm not entirely sure.


Considering the answers so far, I think I would have to change my code to something like this; which I expect is fully legal:

typedef struct {
    int type;
    void *entries;
} Bar;

int main(int argc, char *argv[]) {
    Bar bar;
    bar.entries = malloc(6 * sizeof(long));
    // ...
    long *long_entries = bar.entries;
    long_entries[3] = 123;
    // ...
    free(bar.entries);
}
2

There are 2 best solutions below

0
John Bollinger On BEST ANSWER

If I have a union that contains pointers to different types of data, would it be legal to free malloced memory via a different field than the one it was assigned to? Does it even match the "common initial sequence" rule?

  • What you describe does not satisfy the criteria of the "common initial sequence" rule, as that is about union members that have structure types. Pointers are not structures.

  • Even if we were talking about structures containing pointers as members, pointers types are not compatible if their pointed-to types are not compatible. void and long are not compatible types, and probably Foo is not compatible with either, so the common initial sequence rule would not apply even if you wrapped the pointers in structures.

  • In C, you do not need to rely on the common initial sequence rule to read a different union member than was last written. In practice, it is very common for implementations to use the same representation for all object pointer types, and on such implementations, you probably could use any of those pointer members to free the pointed-to data. HOWEVER, C does not require all object pointer types to use the same representation, and there have historically been implementations in which they didn't. On one of those, the practice you describe most likely would not reliably behave as you intend. Such code can conform to the language spec, but it does not conform strictly. It is not portable.

0
KamilCuk On

Do pointers to different types match the "common initial sequence" rule?

No.

would it be legal to free malloced memory via a different field than the one it was assigned to?

In the context of the question, is free(bar.entries) valid?

I would say this falls into implementation dependent. When you read a different union member that was assigned, the memory is interpreted as the new type. Now, it may happen that when you reinterpret that memory storing a long * as a void *, you will get a proper address which will point to the same long *, in which case bar.entries == bar.long_entries. Or it may not happen. Or you might get a trap representation.

In practice, the code will work on normal architectures, as normal architectures have all pointer types represented in assembly the same.