Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
Let's say we have an object, we store it in a union (into some other narrower type, but with memcpy(3), so it's allowed --I guess--), and then read it from the union via it's original type (so no a...
#5: Post edited
- Let's say we have an object, we store it in a union (into some other narrower type, but with memcpy(3), so it's allowed --I guess--), and then read it from the union via it's original type (so no alignment issues or anything.
- ```c
- $ cat union.c
- #include <string.h>
- struct s { int a; int b; };
- struct t { int a; };
- union u { struct s s; struct t t; };
- int
- main(void)
- {
- struct s x = {42, 53};
- union u y;
- int z;
memcpy(&y.t, &x, sizeof(x)); // y.t has declared type of 'struct t'- z = y.s.b; // Is this UB?
- return z;
- }
- ```
- I would guess the above is undefined behavior, exactly at the point of the read of `y.s.b`.
- The reason is that since we created an object of type `struct t` via memcpy(3), then the compiler is free to assume that the object is no wider than `sizeof(struct t)`, and so `y.s.b` (which is beyond that) would be "uninitialized" (even though we really wrote bytes to it).
- Is it UB as I expect?
- However, neither GCC and Clang complain about such program:
- ```sh
- $ gcc-13 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fanalyzer -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- $ clang-16 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- ```
- ---
- BTW, does it change if I change and use allocated memory?
- ```c
- int
- main(void)
- {
- struct s x = {42, 53};
- union u *y = xmalloc(sizeof(union u)); // No declared/effective type
- int z;
- memcpy(&y->t, &x, sizeof(x)); // This sets the effective type to 'struct s'
- z = y->s.b; // No UB?
- return z;
- }
- ```
- Let's say we have an object, we store it in a union (into some other narrower type, but with memcpy(3), so it's allowed --I guess--), and then read it from the union via it's original type (so no alignment issues or anything.
- ```c
- $ cat union.c
- #include <string.h>
- struct s { int a; int b; };
- struct t { int a; };
- union u { struct s s; struct t t; };
- int
- main(void)
- {
- struct s x = {42, 53};
- union u y;
- int z;
- memcpy(&y.t, &x, sizeof(x)); // y.t has declared/effective type of 'struct t'
- z = y.s.b; // Is this UB?
- return z;
- }
- ```
- I would guess the above is undefined behavior, exactly at the point of the read of `y.s.b`.
- The reason is that since we created an object of type `struct t` via memcpy(3), then the compiler is free to assume that the object is no wider than `sizeof(struct t)`, and so `y.s.b` (which is beyond that) would be "uninitialized" (even though we really wrote bytes to it).
- Is it UB as I expect?
- However, neither GCC and Clang complain about such program:
- ```sh
- $ gcc-13 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fanalyzer -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- $ clang-16 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- ```
- ---
- BTW, does it change if I change and use allocated memory?
- ```c
- int
- main(void)
- {
- struct s x = {42, 53};
- union u *y = xmalloc(sizeof(union u)); // No declared/effective type
- int z;
- memcpy(&y->t, &x, sizeof(x)); // This sets the effective type to 'struct s'
- z = y->s.b; // No UB?
- return z;
- }
- ```
#4: Post edited
- Let's say we have an object, we store it in a union (into some other narrower type, but with memcpy(3), so it's allowed --I guess--), and then read it from the union via it's original type (so no alignment issues or anything.
- ```c
- $ cat union.c
- #include <string.h>
- struct s { int a; int b; };
- struct t { int a; };
- union u { struct s s; struct t t; };
- int
- main(void)
- {
- struct s x = {42, 53};
- union u y;
- int z;
memcpy(&y.t, &x, sizeof(x));- z = y.s.b; // Is this UB?
- return z;
- }
- ```
- I would guess the above is undefined behavior, exactly at the point of the read of `y.s.b`.
- The reason is that since we created an object of type `struct t` via memcpy(3), then the compiler is free to assume that the object is no wider than `sizeof(struct t)`, and so `y.s.b` (which is beyond that) would be "uninitialized" (even though we really wrote bytes to it).
- Is it UB as I expect?
- However, neither GCC and Clang complain about such program:
- ```sh
- $ gcc-13 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fanalyzer -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- $ clang-16 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- ```
- Let's say we have an object, we store it in a union (into some other narrower type, but with memcpy(3), so it's allowed --I guess--), and then read it from the union via it's original type (so no alignment issues or anything.
- ```c
- $ cat union.c
- #include <string.h>
- struct s { int a; int b; };
- struct t { int a; };
- union u { struct s s; struct t t; };
- int
- main(void)
- {
- struct s x = {42, 53};
- union u y;
- int z;
- memcpy(&y.t, &x, sizeof(x)); // y.t has declared type of 'struct t'
- z = y.s.b; // Is this UB?
- return z;
- }
- ```
- I would guess the above is undefined behavior, exactly at the point of the read of `y.s.b`.
- The reason is that since we created an object of type `struct t` via memcpy(3), then the compiler is free to assume that the object is no wider than `sizeof(struct t)`, and so `y.s.b` (which is beyond that) would be "uninitialized" (even though we really wrote bytes to it).
- Is it UB as I expect?
- However, neither GCC and Clang complain about such program:
- ```sh
- $ gcc-13 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fanalyzer -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- $ clang-16 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- ```
- ---
- BTW, does it change if I change and use allocated memory?
- ```c
- int
- main(void)
- {
- struct s x = {42, 53};
- union u *y = xmalloc(sizeof(union u)); // No declared/effective type
- int z;
- memcpy(&y->t, &x, sizeof(x)); // This sets the effective type to 'struct s'
- z = y->s.b; // No UB?
- return z;
- }
- ```
#3: Post edited
Storing more bytes than a union member has, but less than the union size
- Storing more bytes than a union member has, but less than the union size, with memcpy(3)
#2: Post edited
Let's say we have an object, we store it in a union (via some other narrower type, but with memcpy(3), so it's allowed --I guess--), and then read it from the union via it's original type (so no alignment issues or anything.- ```c
- $ cat union.c
- #include <string.h>
- struct s { int a; int b; };
- struct t { int a; };
- union u { struct s s; struct t t; };
- int
- main(void)
- {
- struct s x = {42, 53};
- union u y;
- int z;
- memcpy(&y.t, &x, sizeof(x));
- z = y.s.b; // Is this UB?
- return z;
- }
- ```
- I would guess the above is undefined behavior, exactly at the point of the read of `y.s.b`.
- The reason is that since we created an object of type `struct t` via memcpy(3), then the compiler is free to assume that the object is no wider than `sizeof(struct t)`, and so `y.s.b` (which is beyond that) would be "uninitialized" (even though we really wrote bytes to it).
- Is it UB as I expect?
- However, neither GCC and Clang complain about such program:
- ```sh
- $ gcc-13 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fanalyzer -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- $ clang-16 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- ```
- Let's say we have an object, we store it in a union (into some other narrower type, but with memcpy(3), so it's allowed --I guess--), and then read it from the union via it's original type (so no alignment issues or anything.
- ```c
- $ cat union.c
- #include <string.h>
- struct s { int a; int b; };
- struct t { int a; };
- union u { struct s s; struct t t; };
- int
- main(void)
- {
- struct s x = {42, 53};
- union u y;
- int z;
- memcpy(&y.t, &x, sizeof(x));
- z = y.s.b; // Is this UB?
- return z;
- }
- ```
- I would guess the above is undefined behavior, exactly at the point of the read of `y.s.b`.
- The reason is that since we created an object of type `struct t` via memcpy(3), then the compiler is free to assume that the object is no wider than `sizeof(struct t)`, and so `y.s.b` (which is beyond that) would be "uninitialized" (even though we really wrote bytes to it).
- Is it UB as I expect?
- However, neither GCC and Clang complain about such program:
- ```sh
- $ gcc-13 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fanalyzer -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- $ clang-16 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fsanitize=undefined -fsanitize=address
- $ ./a.out; echo $?
- 53
- ```
#1: Initial revision
Storing more bytes than a union member has, but less than the union size
Let's say we have an object, we store it in a union (via some other narrower type, but with memcpy(3), so it's allowed --I guess--), and then read it from the union via it's original type (so no alignment issues or anything. ```c $ cat union.c #include <string.h> struct s { int a; int b; }; struct t { int a; }; union u { struct s s; struct t t; }; int main(void) { struct s x = {42, 53}; union u y; int z; memcpy(&y.t, &x, sizeof(x)); z = y.s.b; // Is this UB? return z; } ``` I would guess the above is undefined behavior, exactly at the point of the read of `y.s.b`. The reason is that since we created an object of type `struct t` via memcpy(3), then the compiler is free to assume that the object is no wider than `sizeof(struct t)`, and so `y.s.b` (which is beyond that) would be "uninitialized" (even though we really wrote bytes to it). Is it UB as I expect? However, neither GCC and Clang complain about such program: ```sh $ gcc-13 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fanalyzer -fsanitize=undefined -fsanitize=address $ ./a.out; echo $? 53 $ clang-16 -Wall -Wextra -Wpedantic -pedantic-errors union.c -O3 -fsanitize=undefined -fsanitize=address $ ./a.out; echo $? 53 ```