Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clang feature request: warn on incorrect tagged union value access #74205

Open
matheusmoreira opened this issue Dec 2, 2023 · 3 comments
Open
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" enhancement Improving things as opposed to bug fixing, e.g. new or missing feature

Comments

@matheusmoreira
Copy link

Currently clang does not produce a warning if the value of a tagged union that doesn't correspond to its type tag is accessed.

For example, this code:

// warn.c
#include <stdio.h>

enum T { I, F };
union U { int i; float f; };
struct S { enum T t; union U u; };

int main(void) {
	struct S s = { .t = F, .u.f = 12345.67890f };
	switch (s.t) {
	case I:
		printf("%d\n", s.u.i);
		break;
	case F:
		// copied the above case
		// but neglected to update the code
		printf("%d\n", s.u.i);
		break;
	}
}

Does not produce any warning when compiled, leading to incorrect results:

$ clang -Weverything -o warn warn.c && ./warn
1178658487

I understand that unions are typically used for type punning and that such accesses are often intended by the programmer but compiler checks would still be beneficial when that's not the case. People have created C preprocessor solutions to use tagged unions safely in C. I've also seen support for safe tagged unions in newer languages like Zig.

A compiler mechanism to establish a relationship between the union values and their corresponding enum tags would be extremely useful. Something like this, perhaps:

struct S {
	enum T t;
	union U {
		int i       __attribute__((tag(t, I)));
		float f     __attribute__((tag(t, F)));
	} u;
};

Then clang would be able to warn when union values are accessed in a context where their specified tags are not known to be the correct value:

	switch (s.t) {
	case I:
		// i is accessed
		// the tag of i is t
		// t is supposed to equal I
		// compiler knows t equals I because of switch case
		// correct, no warning is emitted
		printf("%d\n", s.u.i);
		break;
	case F:
		// i is accessed
		// the tag of i is t
		// t is supposed to equal I
		// compiler knows t equals F because of switch case
		// incorrect, a warning is emitted
		printf("%d\n", s.u.i);
		break;
	}

Relevant links:

@github-actions github-actions bot added the clang Clang issues not falling into any other category label Dec 2, 2023
@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" and removed clang Clang issues not falling into any other category labels Dec 3, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Dec 3, 2023

@llvm/issue-subscribers-clang-frontend

Author: Matheus Moreira (matheusmoreira)

Currently `clang` does not produce a warning if the value of a tagged union that doesn't correspond to its type tag is accessed.

For example, this code:

// warn.c
#include &lt;stdio.h&gt;

enum T { I, F };
union U { int i; float f; };
struct S { enum T t; union U u; };

int main(void) {
	struct S s = { .t = F, .u.f = 12345.67890f };
	switch (s.t) {
	case I:
		printf("%d\n", s.u.i);
		break;
	case F:
		// copied the above case
		// but neglected to update the code
		printf("%d\n", s.u.i);
		break;
	}
}

Does not produce any warning when compiled, leading to incorrect results:

$ clang -Weverything -o warn warn.c &amp;&amp; ./warn
1178658487

I understand that unions are typically used for type punning and that such accesses are often intended by the programmer but compiler checks would still be beneficial when that's not the case. People have created C preprocessor solutions to use tagged unions safely in C. I've also seen support for safe tagged unions in newer languages like Zig.

A compiler mechanism to establish a relationship between the union values and their corresponding enum tags would be extremely useful. Something like this, perhaps:

struct S {
	enum T t;
	union U {
		int i       __attribute__((tag(t, I)));
		float f     __attribute__((tag(t, F)));
	} u;
};

Then clang would be able to warn when union values are accessed in a context where their specified tags are not known to be the correct value:

	switch (s.t) {
	case I:
		// i is accessed
		// the tag of i is t
		// t is supposed to equal I
		// compiler knows t equals I because of switch case
		// correct, no warning is emitted
		printf("%d\n", s.u.i);
		break;
	case F:
		// i is accessed
		// the tag of i is t
		// t is supposed to equal I
		// compiler knows t equals F because of switch case
		// incorrect, a warning is emitted
		printf("%d\n", s.u.i);
		break;
	}

Relevant links:

  • lone-lang/lone#1

@tbaederr tbaederr added the enhancement Improving things as opposed to bug fixing, e.g. new or missing feature label Dec 3, 2023
@matheusmoreira
Copy link
Author

Equivalent issue on the GCC issue tracker:

112840 - feature request: warn on incorrect tagged union value access

@matheusmoreira
Copy link
Author

Proposal in the GCC Bugzilla: a general guard attribute that produces a warning in case the compiler can't statically evauate the expression as true.

struct S {
    enum T t;
    union U {
        int i       [[gnu::guard(.t == I)]];
        float f     [[gnu::guard(.t == F)]];
    } u;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" enhancement Improving things as opposed to bug fixing, e.g. new or missing feature
Projects
None yet
Development

No branches or pull requests

4 participants