-1

I was currently reading about some strict aliasing rules, and I was wondering whether casting a pointer to an incomplete struct is undefined behavior.

Example 1:

#include <stdlib.h>

struct abc;

int main(int argc, char *argv[])
{
  struct abc *mystruct;
  char *buf;

  buf = malloc(100);
  mystruct = (struct abc*)buf;

  // and then mystruct could be submitted to a function, where it is
  // casted back to a "char *", the "struct abc" will never be completed.

  return 0;
}

Example 2:

struct abc1;
struct abc2;

int foo(struct abc1 *mystruct1)
{
  struct abc2 *mystruct2;

  mystruct2 = (struct abc2 *)mystruct1;

  // and then mystruct2 could be submitted to a function, where it is
  // casted to a "char *", both structs stay incomplete.

  return 0;
}

So, my question: Is casting pointers to incomplete structs like in those two examples prohibited by the c11 standard, and if so, which part of the standard does forbid it?

Julius
  • 1,155
  • 9
  • 19
  • 1
    Casting between pointers to struct types is fine by itself. The question is what specifically do you do with those pointers afterward. A more complete example would help. – dbush Dec 26 '18 at 14:49
  • @dbush Casting the struct pointer back to a ``char *`` is the only thing which is done afterwards. The ``char *`` is then read and modified. The structs will never be complete. However, I was reading that having two incompatible types pointing to the same object can be invalid, is that false? – Julius Dec 26 '18 at 14:55
  • 2
    Strict aliasing comes into play if you read an object of one type via a pointer to another type (other than `char *`). I don't see that happening here. – dbush Dec 26 '18 at 15:00

1 Answers1

3

One key relevant part of the standard is C11 §6.2.5 Types ¶28:

28 A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.48) Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.

48) The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.

Another is §6.3 Conversions and particularly §6.3.2.3 Pointers ¶7:

7 A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned68) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.

68) In general, the concept ''correctly aligned'' is transitive: if a pointer to type A is correctly aligned for a pointer to type B, which in turn is correctly aligned for a pointer to type C, then a pointer to type A is correctly aligned for a pointer to type C.

Thus, my understanding is that there is no problem with either example code fragment shown in the question. The structure types are incomplete, but that is not a problem for the operations shown. The 'and then' sections of the code need not be problematic — it depends on what is actually there.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thank you! What about [6.7](http://port70.net/~nsz/c/c11/n1570.html#6.7p4) and [UB](http://port70.net/~nsz/c/c11/n1570.html#J.2) ``An object is assigned to an inexactly overlapping object or to an exactly overlapping object with incompatible type`` - are the provided examples not affected by this? – Julius Dec 26 '18 at 15:17
  • The only objects in the examples are pointers (to incomplete structure types). The assignments are all kosher; there are no inexactly overlapping objects, and the types are not not incompatible — though that section of the standard ([§6.2.7 Compatible type and composite type](http://port70.net/~nsz/c/c11/n1570.html#6.2.7) is one of the more inscrutable ones. One thing it defines is that separate translation units with the same text for the types can be used to create code that can be linked together to make a coherent program. I don't think that §6.7 ¶4 or UB is applicable here. – Jonathan Leffler Dec 26 '18 at 15:25
  • I'm trying to understand the sentence `All pointers to structure types shall have the same representation and alignment requirements as each other` but I'm struggling. Can you please explain in details? does it means that all pointers in my programs that points to many different structures, has same address alignment? and if so, what is the alignment value? and what `same representation` means? – izac89 Dec 26 '18 at 17:27
  • 1
    @user2162550: Ouch — good question, complex answer. First off, it means that all pointers to structures are the same size, regardless of the structure type. So, `sizeof(struct Foo *) == sizeof(struct Bar *)` independent of how (or even if) the bodies of the structures are defined. Second, it means that if a `struct Foo *` needs to be aligned on an 8-byte boundary, so does a `struct Bar *`. The 'same representation' requirement imposes conditions on machines (mainframes) that used to exist but are mainly museum pieces now — they're probably less powerful than your cell phone. _[…continued…]_ – Jonathan Leffler Dec 26 '18 at 17:38
  • 1
    _[…continuation…]_ Some mainframes had complex hardware descriptors for things like pointers which provided checking on whether the pointer was being abused. The 'same representation' rule is saying that those machines can't object to converting a `struct Foo *` into a `struct Bar *` or vice versa. I'm not sure if they're allowed to complain if you used the converted pointer to access the wrong type. However, such machines are now rarely found in the field. See Wikipedia on [ICL 2900 Series](https://en.wikipedia.org/wiki/ICL_2900_Series) for one example (3 mips; 8 MiB memory). – Jonathan Leffler Dec 26 '18 at 17:43