Undefined behavior with type casting? - c

Take the following example:
typedef struct array_struct {
unsigned char* pointer;
size_t length;
} array;
typedef struct vector_struct {
unsigned char* pointer;
// Reserved is the amount of allocated memory not being used.
// MemoryLength = length + reserved;
size_t length, reserved;
} vector;
// Example Usage:
vector* vct = (vector*) calloc(sizeof(vector), 1);
vct->reserved = 0;
vct->length = 24;
vct->pointer = (unsigned char*) calloc(arr->length, 1);
array* arr = (array*) vct;
printf("%i", arr->length);
free(arr->pointer);
free(arr);
C seems to allocate memory for struct members in the order they're defined in the struct. Which means that if you cast vector -> array you'll still get the same results if you perform operations on array as you would as if you did it on vector since they have the same members and order of members.
As long as you only down cast from vector -> array as if array was a generic type for vector you shouldn't run into any problems.
Is this undefined and bad behavior despite the similar structure of the types?

This is well-defined behavior if you permit type aliasing (which C doesn't but most compilers do, either by default or by some compilation flag), and it is undefined behavior if you prohibit this type of type aliasing (which is commonly referred to as "strict aliasing" because the rules are pretty strict). From the N1570 draft of the C standard:
6.5.2.3
6 One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the complete type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.
That section is about unions, but in order for that behavior to be legal in unions, it restricts padding possibilities and thus requires the two structures to share a common layout and initial padding. So we've got that going for us.
Now, for strict aliasing, the standard says:
6.5
7 An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
a type compatible with the effective type of the object
[...]
A "compatible type" is:
6.2.7
1 Two types have compatible type if their types are the same.
It goes on to explain that more and list a few cases that have a little more "wiggle room" but none of them apply here. Unfortunately for you, the buck stops here. This is undefined behavior.
Now, one thing you could do to get around this would be:
typedef struct array_struct {
unsigned char* pointer;
size_t length;
} array;
typedef struct vector_struct {
array array;
size_t reserved;
} vector;

Related

Is casting from char * to other compatibly-aligned pointer types defined behavior in C89?

Are explicit casts from char * to other pointer types fully defined behavior according to ANSI C89 if the pointer is guaranteed to meet the alignment requirements of the type you're casting to? Here's an example of what I mean:
/* process.c */
void *process(size_t elem_size, size_t cap) {
void *arr;
assert(cap > 5);
arr = malloc(elem_size * cap);
/* set id of element 5 to 0xffffff */
*(long *)((char *)arr + elem_size*5) = 0xffffff;
/* rest of the code omitted */
return arr;
}
/* main.c */
struct some_struct { long id; /* other members omitted */ };
struct other_struct { long id; /* other members omitted */ };
int main(int argc, char **argv) {
struct some_struct *s = process(sizeof(struct some_struct), 40);
printf("%lx\n", s[5].id);
return 0;
}
This code compiles without warnings and works as expected on my machine but I'm not fully sure if these kinds of casts are defined behavior.
C89 draft, section 4.10.3 (Memory management functions):
The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object in the space allocated (until the space is explicitly freed or reallocated).
C89 draft, section 3.3.4 (Cast operators):
A pointer to an object or incomplete type may be converted to a pointer to a different object type or a different incomplete type. The resulting pointer might not be valid if it is improperly aligned for the type pointed to. It is guaranteed, however, that a pointer to an object of a given alignment may be converted to a pointer to an object of the same alignment or a less strict alignment and back again; the result shall compare equal to the original pointer.
This clearly specifies what happens if you cast from struct some_struct * to char * and back to struct some_struct * but in my case the code responsible for allocation doesn't have access to the full struct definition so it can't initially specify the pointer type to be struct some_struct * so I'm not sure if the rule still applies.
If the code I posted is technically UB, is there another standards-compliant way to modify array elements without knowing their full type? Are there real-world impementations where you would expect it to do something else than ((struct some_struct *)arr)[5].id = 0xffffff;?
This code compiles without warnings and works as expected on my machine but I'm not fully sure if these kinds of casts are defined behavior.
In general, the casts have defined behavior, but that behavior can be that the result is not a valid pointer. Thus dereferencing the result of the cast may produce UB.
Considering only function process(), then, it is possible that the result of its evaluation of (long *)((char *)arr + elem_size*5) is an invalid pointer. If and only if it is invalid, the attempt to use it to assign a value to the object it hypothetically points to produces UB.
However, main()s particular usage of that function is fine:
In process(), the pointer returned by malloc and stored in arr is suitably aligned for a struct some_struct (and for any other type).
The compiler must choose a size and layout for struct some_struct such that every element and every member of every element of an array of such structures is properly aligned.
Arrays are composed of contiguous objects of the array's element type, without gaps (though the element types themselves may contain padding if they are structures or unions).
Therefore, (char *)arr + n * sizeof(struct some_struct) must be suitably aligned for a struct some_struct, for any integer n such that the result points within or just past the end of the allocated region. This computation is closely related to the computations involved in accessing an array of struct some_struct via the indexing operator.
struct some_struct has a long as its first member, and that member must appear at offset 0 from the beginning of the struct. Therefore, every pointer that is suitably aligned for a struct some_struct must also be suitably aligned for a long.
Determining whether an operation upholds or violates "type aliasing" constraints requires being able to answer two questions:
For purposes of the aliasing rules, when does a region of storage hold an "object" of a particular type.
For purposes of the aliasing rules, is a particular access performed "by" an lvalue expression of a particular type.
For your question, the second issue above is the most the relevant: if a pointer or lvalue of type T1 is used to derive a value of type T2* which is dereferenced to access storage, the access may sometimes need to be regarded for purposes of aliasing as though performed by an lvalue of type T1, and sometimes as though performed by one of type T2, but the Standard fails to offer any guidance as to which interpretation should apply when. Constructs like yours would be processed predictably by implementation that didn't abuse the Standard as an excuse to behave nonsensically, but could be processed nonsensically by conforming but obtuse implementations that do abuse the Standard in such fashion.
The authors of C89 didn't expect anyone to care about the precise boundaries between constructs whose behavior was defined by the Standard, versus those which all implementations were expected to process identically but which the Standard didn't actually define, and thus saw no need to define the terms "object" and "by" with sufficient precision to unambiguously answer the above questions in ways that would yield defined program behavior in all sensible cases.

Are pointers to union required to be aligned for all members

Given
typedef union { unsigned char b; long l; } BYTE_OR_LONG;
would it be legitimate to have a function
unsigned long get_byte_or_long(BYTE_OR_LONG *it)
{
if (it->b)
return it->b;
else
return decode_long(it->l); // Platform-dependent method
// Could return (it), (it>>8), etc.
}
and call it
void test()
{
long l = encode_long(12345678); // Platform-dependent; could return
// (it<<8), (it & 16777215), etc.
char b[2] = {12,34};
BYTE_OR_LONG *bl[3];
bl[0] = (BYTE_OR_LONG*)&l;
bl[1] = (BYTE_OR_LONG*)b;
bl[2] = (BYTE_OR_LONG*)(b+1);
for (int i=0; i<3; i++)
printf("%lu\n", get_byte_or_long(bl[i]));
}
Certainly constructing an unaligned BYTE_OR_LONG *p and then accessing p->l would be Undefined Behavior. Further, even the act of casting an unaligned pointer to (unsigned long*) would be Undefined Behavior, since an implementation might not need as many bits for such a type as for a char*. With a union, however, things seem unclear.
From what I understand, a pointer to a union is supposed to be equivalent to a pointer to any of its elements. Does that mean that implementations required to guarantee that a pointer to a union type must be capable of identifying any instance of any type contained therein [thus a BYTE_OR_LONG* would have to be able to identify any unsigned char], or are programmers required to only cast to union types pointers which would satisfy every alignment requirement of every constituent therein?
Does that mean that implementations required to guarantee that a pointer to a union type must be capable of identifying any instance of any type contained therein ... ?
Long question, short answer: Yes.
(I'll dig out the Standard reference later)
Basically it's because a struct/union's 1st element is guaranteed to carry no padding before it.
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned [...] for the referenced type, the behavior is undefined. [C11 (n1570) 6.3.2.3 p7]
I couldn't find any explicit guarantees about the alignment requirements of unions, so the conversion to the union pointer appears not strictly conforming. On my machine, _Alignof(char) is 1, but _Alignof(BYTE_OR_LONG) is 4.
Does that mean that implementations required to guarantee that a pointer to a union type must be capable of identifying any instance of any type contained therein [thus a BYTE_OR_LONG* would have to be able to identify any unsigned char], or are programmers required to only cast to union types pointers which would satisfy every alignment requirement of every constituent therein?
No, a pointer to T may be made point to any union containing a T, not necessarily the other way round. As far as I know, the alignment requirements of a union could even be stricter than those of all of its members.

Casting structure pointers between structs containing pointers to different types?

I have a structure, defined by as follows:
struct vector
{
(TYPE) *items;
size_t nitems;
};
where type may literally be any type, and I have a type-agnostic structure of similar kind:
struct _vector_generic
{
void *items;
size_t nitems;
};
The second structure is used to pass structures of the first kind of any type to a resizing function, for example like this:
struct vector v;
vector_resize((_vector_generic*)&v, sizeof(*(v->items)), v->nitems + 1);
where vector_resize attempts to realloc memory for the given number of items in the vector.
int
vector_resize (struct _vector_generic *v, size_t item_size, size_t length)
{
void *new = realloc(v->items, item_size * length);
if (!new)
return -1;
v->items = new;
v->nitems = length;
return 0;
}
However, the C standard states that pointers to different types are not required to be of the same size.
6.2.5.27:
A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type.39) 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.
Now my question is, should I be worried that this code may break on some architectures?
Can I fix this by reordering my structs such that the pointer type is at the end? for example:
struct vector
{
size_t nitems;
(TYPE) *items;
};
And if not, what can I do?
For reference of what I am trying to achieve, see:
https://github.com/andy-graprof/grapes/blob/master/grapes/vector.h
For example usage, see:
https://github.com/andy-graprof/grapes/blob/master/tests/grapes.tests/vector.exp
You code is undefined.
Accessing an object using an lvalue of an incompatible type results in undefined behavior.
Standard defines this in:
6.5 p7:
An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the
object,
— a type that is the signed or unsigned type corresponding to a qualified version of the
effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
struct vector and struct _vector_generic have incompatible types and do not fit into any of the above categories. Their internal representation is irrelevant in this case.
For example:
struct vector v;
_vector_generic* g = &v;
g->size = 123 ; //undefined!
The same goes for you example where you pass the address of the struct vector to the function and interpret it as a _vector_generic pointer.
The sizes and padding of the structs could also be different causing elements to be positioned at different offsets.
What you can do is use your generic struct, and cast if depending on the type the void pointer holds in the main code.
struct gen
{
void *items;
size_t nitems;
size_t nsize ;
};
struct gen* g = malloc( sizeof(*g) ) ;
g->nitems = 10 ;
g->nsize = sizeof( float ) ;
g->items = malloc( g->nsize * g->nitems ) ;
float* f = g->items ;
f[g->nitems-1] = 1.2345f ;
...
Using the same struct definition you can allocate for a different type:
struct gen* g = malloc( sizeof(*g) ) ;
g->nitems = 10 ;
g->nsize = sizeof( int ) ;
g->items = malloc( g->nsize * g->nitems ) ;
int* i = g->items ;
...
Since you are storing the size of the type and the number of elements, it is obvious how your resize function would look like( try it ).
You will have to be careful to remember what type is used in which variable as the compiler will not warn you because you are using void*.
The code in your question invokes undefined behaviour (UB), because you de-reference a potentially invalid pointer. The cast:
(_vector_generic*)&v
... is covered by 6.3.2.3 paragraph 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 aligned for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.
If we assume alignment requirements are met, then the cast does not invoke UB. However, there is no requirement that the converted pointer must "compare equal" with (i.e. point at the same object as) the original pointer, nor even that it points to any object at all - that is to say, the value of the pointer is unspecified - therefore, to dereference this pointer (without first ascertaining that it is equal to the original) invokes undefined behaviour.
(Many people who know C well find this odd. I think this is because they know a pointer cast usually compiles to no operation - the pointer value simply remains as it is - and therefore they see pointer conversion as purely a type conversion. However, the standard does not mandate this).
Even if the pointer after conversion did compare equal with the original pointer, 6.5 paragraph 7 (the so-called "strict aliasing rule") would not allow you to dereference it. Essentially, you cannot access the same object via two pointers with different type, with some limited exceptions.
Example:
struct a { int n; };
struct b { int member; };
struct a a_object;
struct b * bp = (struct b *) &a_object; // bp takes an unspecified value
// Following would invoke UB, because bp may be an invalid pointer:
// int m = b->member;
// But what if we can ascertain that bp points at the original object?:
if (bp == &a_object) {
// The comparison in the line above actually violates constraints
// in 6.5.9p2, but it is accepted by many compilers.
int m = b->member; // UB if executed, due to 6.5p7.
}
Lets for the sake of discussion ignore that the C standard formally says this is undefined behavior. Because undefined behavior simply means that something is beyond the scope of the language standard: anything can happen and the C standard makes no guarantees. There may however be "external" guarantees on the particular system you are using, made by those who made the system.
And in the real world where there is hardware, there are indeed such guarantees. There are just two things that can go wrong here in practice:
TYPE* having a different representation or size than void*.
Different struct padding in each struct type because of alignment requirements.
Both of these seem unlikely and can be dodged with a static asserts:
static void ct_assert (void) // dummy function never linked or called by anyone
{
struct vector v1;
struct _vector_generic v2;
static_assert(sizeof(v1.items) == sizeof(v2.items),
"Err: unexpected pointer format.");
static_assert(sizeof(v1) == sizeof(v2),
"Err: unexpected padding.");
}
Now the only thing left that could go wrong is if a "pointer to x" has same size but different representation compared to "pointer to y" on your specific system. I have never heard of such a system anywhere in the real world. But of course, there are no guarantees: such obscure, unorthodox systems may exist. In that case, it is up to you whether you want to support them, or if it will suffice to just have portability to 99.99% of all existing computers in the world.
In practice, the only time you have more than one pointer format on a system is when you are addressing memory beyond the CPU's standard address width, which is typically handled by non-standard extensions such as far pointers. In all such cases, the pointers will have different sizes and you will detect such cases with static assert above.

Why does casting a struct address to an int pointer, dereferencing, and using that as the LVALUE in a statement crash my microcontroller?

The following code crashes my microprocessor at runtime.
struct dummytype dummy;
struct crummytype crummy;
*(unsigned int*)&dummy = *(unsigned int*)&crummy;
Assuming both structs are the same size, is there something about this code that is not valid C? Is its validity contingent on anything particular?
This is only valid if both structures have an unsigned int as the first member.
C99 §6.7.2.1/13
Within a structure object, the non-bit-field members and the units in which bit-fields
reside have addresses that increase in the order in which they are declared. A pointer to a
structure object, suitably converted, points to its initial member (or if that member is a
bit-field, then to the unit in which it resides), and vice versa. There may be unnamed
padding within a structure object, but not at its beginning.
Putting that simply, given an address of a structure object, you can cast that address to a pointer-to-first-member-type:
struct A
{
unsigned int n;
char junk[5];
};
struct A a;
unsigned int *p = (unsigned int *)&a; // OK. pointer is proper for first member type
unsigned long*x = (unsigned long *)&a; // BAD
In short, your code is only legitimate if both structure types have an unsigned int for their first member. Anything else is undefined behavior (void * not withstanding, but since it is non-dereferencable, it really isn't applicable here). Each structure type being "big enough" to hold an unsigned int isn't enough. Their first member must actually be an unsigned int.
Even through both structures have same size, overlapping behavior is undefined.
if the structures are like this ,above statement will gives result what you are looking.
struct dummytype
{
int a;
};
struct crummytype
{
int b;
};
if the structures are like this ,you can't say what would be the result.
struct dummytype
{
char name[20];
int a;
};
struct crummytype
{
char name1[20];
int b;
};
It's invalid C by both the alignment requirements of int and the aliasing rules (accessing an object via an lvalue of type different from the effective type of the object).
C99 draft standard states (Annex J):
J.2 Undefined behavior
The behavior is undefined in the following circumstances:
[...]
An object is assigned to an inexactly overlapping object or to an exactly overlapping
object with incompatible type (6.5.16.1).
then, for what concerns compatible types:
6.2.7 Compatible type and composite type
Two types have compatible type if their types are the same. Additional rules for
determining whether two types are compatible are described in 6.7.2 for type specifiers,
in 6.7.3 for type qualifiers, and in 6.7.5 for declarators. Moreover, two structure,
union, or enumerated types declared in separate translation units are compatible if their
tags and members satisfy the following requirements: If one is declared with a tag, the
other shall be declared with the same tag. If both are complete types, then the following
additional requirements apply: there shall be a one-to-one correspondence between their
members such that each pair of corresponding members are declared with compatible
types, and such that if one member of a corresponding pair is declared with a name, the
other member is declared with the same name. For two structures, corresponding
members shall be declared in the same order. For two structures or unions, corresponding
bit-fields shall have the same widths. For two enumerations, corresponding members
shall have the same values.
making the two structs the same size is not sufficient to make them compatible types, so the behavior is undefined.
Edit: for sake of completeness I add the excerpt cited by #PascalCuoq in a comment to another answer in this thread, which is also relevant:
6.5 Expressions
[...]
7
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
a type compatible with the effective type of the object,
a qualified version of a type compatible with the effective type of the object,
a type that is the signed or unsigned type corresponding to the effective type of the
object,
a type that is the signed or unsigned type corresponding to a qualified version of the
effective type of the object,
an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively, a member of a subaggregate or contained union), or
a character type.

Struct pointer compatibility

Suppose we have two structs:
typedef struct Struct1
{
short a_short;
int id;
} Struct1;
typedef struct Struct2
{
short a_short;
int id;
short another_short;
} Struct2;
Is it safe to cast from Struct2 * to Struct1 * ? What does the ANSI spec says about this?
I know that some compilers have the option to reorder structs fields to optimize memory usage, which might render the two structs incompatible. Is there any way to be sure this code will be valid, regardless of the compiler flag?
Thank you!
It is safe, as far as I know.
But it's far better, if possible, to do:
typedef struct {
Struct1 struct1;
short another_short;
} Struct2;
Then you've even told the compiler that Struct2 starts with an instance of Struct1, and since a pointer to a struct always points at its first member, you're safe to treat a Struct2 * as a Struct1 *.
struct pointers types always have the same representation in C.
(C99, 6.2.5p27) "All pointers to structure types shall have the same
representation and alignment requirements as each other."
And members in structure types are always in order in C.
(C99, 6.7.2.1p5) "a structure is a type consisting of a sequence of
members, whose storage is allocated in an ordered sequence"
No, the standard does't allow this; accessing the elements of a Struct2 object through a Struct1 pointer is undefined behavior. Struct1 and Struct2 are not compatible types (as defined in 6.2.7) and may be padded differently, and accessing them via the wrong pointer also violates aliasing rules.
The only way something like this is guaranteed to work is when Struct1 is included in Struct2 as its initial member (6.7.2.1.15 in the standard), as in unwind's answer.
The language specification contains the following guarantee
6.5.2.3 Structure and union members
6 One special guarantee is made in order to simplify the use of unions: if a union contains
several structures that share a common initial sequence (see below), and if the union
object currently contains one of these structures, it is permitted to inspect the common
initial part of any of them anywhere that a declaration of the completed type of the union
is visible. Two structures share a common initial sequence if corresponding members
have compatible types (and, for bit-fields, the same widths) for a sequence of one or more
initial members.
This only applies to type-punning through unions. However, this essentially guarantees that the initial portions of these struct types will have identical memory layout, including padding.
The above does not necessarily allow one to do the same by casting unrelated pointer types. Doing so might constitute a violation of aliasing rules
6.5 Expressions
7 An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the
object,
— a type that is the signed or unsigned type corresponding to a qualified version of the
effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
The only question here is whether accessing
((Struct1 *) struct2_ptr)->a_short
constitutes access to the whole Struct2 object (in which case it is a violation of 6.5/7 and it is undefined), or merely access to a short object (in which case it might be perfectly defined).
It general, it might be a good idea to stick to the following rule: type-punning is allowed through unions but not through pointers. Don't do it through pointers, even if you are dealing with two struct types with a common initial subsequence of members.
It will most probably work. But you are very correct in asking how you can be sure this code will be valid. So: somewhere in your program (at startup maybe) embed a bunch of ASSERT statements which make sure that offsetof( Struct1.a_short ) is equal to offsetof( Struct2.a_short ) etc. Besides, some programmer other than you might one day modify one of these structures but not the other, so better safe than sorry.
Yes, it is ok to do that!
A sample program is as follows.
#include <stdio.h>
typedef struct Struct1
{
short a_short;
int id;
} Struct1;
typedef struct Struct2
{
short a_short;
int id;
short another_short;
} Struct2;
int main(void)
{
Struct2 s2 = {1, 2, 3};
Struct1 *ptr = &s2;
void *vp = &s2;
Struct1 *s1ptr = (Struct1 *)vp;
printf("%d, %d \n", ptr->a_short, ptr->id);
printf("%d, %d \n", s1ptr->a_short, s1ptr->id);
return 0;
}

Resources