[PATCH] D154696: [Clang] Diagnose jumps into statement expressions
Nathan Chancellor via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 12 08:30:43 PDT 2023
nathanchance added subscribers: nickdesaulniers, nathanchance.
nathanchance added a comment.
This patch breaks building the Linux kernel for PowerPC, which uses `asm goto` with a local label in a statement expression for the WARN macro. It seems like something with the scoping is going wrong.
I have two reproducers. The first is manually reduced from the kernel sources:
struct rb_node {
unsigned long __rb_parent_color;
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
struct rb_root {
struct rb_node *rb_node;
};
struct kernfs_elem_dir {
struct rb_root children;
};
struct kernfs_node {
struct kernfs_elem_dir dir;
unsigned short flags;
};
enum kernfs_node_flag {
KERNFS_ACTIVATED = 0x0010,
KERNFS_NS = 0x0020,
KERNFS_HAS_SEQ_SHOW = 0x0040,
KERNFS_HAS_MMAP = 0x0080,
KERNFS_LOCKDEP = 0x0100,
KERNFS_HIDDEN = 0x0200,
KERNFS_SUICIDAL = 0x0400,
KERNFS_SUICIDED = 0x0800,
KERNFS_EMPTY_DIR = 0x1000,
KERNFS_HAS_RELEASE = 0x2000,
KERNFS_REMOVING = 0x4000,
};
enum kernfs_node_type {
KERNFS_DIR = 0x0001,
KERNFS_FILE = 0x0002,
KERNFS_LINK = 0x0004,
};
#define KERNFS_TYPE_MASK 0x000f
struct bug_entry {
signed int bug_addr_disp;
signed int file_disp;
unsigned short line;
unsigned short flags;
};
static enum kernfs_node_type kernfs_type(struct kernfs_node *kn)
{
return kn->flags & KERNFS_TYPE_MASK;
}
void kernfs_enable_ns(struct kernfs_node *kn)
{
({
int __ret_warn_on = !!(kernfs_type(kn) != KERNFS_DIR);
if (__builtin_expect(!!(__ret_warn_on), 0))
do {
__label__ __label_warn_on;
asm goto("1: "
"twi 31, 0, 0"
"\n"
".section __ex_table,\"a\";"
" "
".balign 4;"
" "
".long (1b) - . ;"
" "
".long (%l[__label_warn_on]) - . ;"
" "
".previous"
" "
".section __bug_table,\"aw\"\n"
"2: .4byte 1b - .\n"
" .4byte %0 - .\n"
" .short %1, %2\n"
".org 2b+%3\n"
".previous\n"
:
: "i"("include/linux/kernfs.h"),
"i"(378),
"i"((1 << 0) |
((1 << 1) | ((9) << 8))),
"i"(sizeof(struct bug_entry))
:
: __label_warn_on);
do {
} while (0);
__builtin_unreachable();
__label_warn_on:
break;
} while (0);
__builtin_expect(!!(__ret_warn_on), 0);
});
({
int __ret_warn_on = !!(!(
({
do {
__attribute__((
__noreturn__)) extern void
__compiletime_assert_244(void)
__attribute__((__error__(
"Unsupported access size for {READ,WRITE}_ONCE().")));
if (!((sizeof((&kn->dir.children)
->rb_node) ==
sizeof(char) ||
sizeof((&kn->dir.children)
->rb_node) ==
sizeof(short) ||
sizeof((&kn->dir.children)
->rb_node) ==
sizeof(int) ||
sizeof((&kn->dir.children)
->rb_node) ==
sizeof(long)) ||
sizeof((&kn->dir.children)
->rb_node) ==
sizeof(long long)))
__compiletime_assert_244();
} while (0);
(*(const volatile typeof(_Generic(
((&kn->dir.children)->rb_node),
char: (char)0,
unsigned char: (unsigned char)0,
signed char: (signed char)0,
unsigned short: (unsigned short)0,
signed short: (signed short)0,
unsigned int: (unsigned int)0,
signed int: (signed int)0,
unsigned long: (unsigned long)0,
signed long: (signed long)0,
unsigned long long: (
unsigned long long)0,
signed long long: (signed long long)0,
default: ((&kn->dir.children)->rb_node)))
*)&((&kn->dir.children)->rb_node));
}) == ((void *)0)));
if (__builtin_expect(!!(__ret_warn_on), 0))
do {
__label__ __label_warn_on;
asm goto("1: "
"twi 31, 0, 0"
"\n"
".section __ex_table,\"a\";"
" "
".balign 4;"
" "
".long (1b) - . ;"
" "
".long (%l[__label_warn_on]) - . ;"
" "
".previous"
" "
".section __bug_table,\"aw\"\n"
"2: .4byte 1b - .\n"
" .4byte %0 - .\n"
" .short %1, %2\n"
".org 2b+%3\n"
".previous\n"
:
: "i"("include/linux/kernfs.h"),
"i"(379),
"i"((1 << 0) |
((1 << 1) | ((9) << 8))),
"i"(sizeof(struct bug_entry))
:
: __label_warn_on);
do {
} while (0);
__builtin_unreachable();
__label_warn_on:
break;
} while (0);
__builtin_expect(!!(__ret_warn_on), 0);
});
kn->flags |= KERNFS_NS;
}
$ ../install/llvm-good/bin/clang --target=powerpc64le-linux-gnu -c -o /dev/null test.c
test.c:93:3: warning: ignoring return value of function declared with const attribute [-Wunused-value]
93 | __builtin_expect(!!(__ret_warn_on), 0);
| ^~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
test.c:174:3: warning: ignoring return value of function declared with const attribute [-Wunused-value]
174 | __builtin_expect(!!(__ret_warn_on), 0);
| ^~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
$ ../install/llvm-bad/bin/clang --target=powerpc64le-linux-gnu -c -o /dev/null test.c
test.c:93:3: warning: ignoring return value of function declared with const attribute [-Wunused-value]
93 | __builtin_expect(!!(__ret_warn_on), 0);
| ^~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
test.c:174:3: warning: ignoring return value of function declared with const attribute [-Wunused-value]
174 | __builtin_expect(!!(__ret_warn_on), 0);
| ^~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
test.c:60:5: error: cannot jump from this asm goto statement to one of its possible targets
60 | asm goto("1: "
| ^
test.c:171:1: note: possible target of asm goto statement
171 | __label_warn_on:
| ^
test.c:95:2: note: jump enters a statement expression
95 | ({
| ^
test.c:141:5: error: cannot jump from this asm goto statement to one of its possible targets
141 | asm goto("1: "
| ^
test.c:90:1: note: possible target of asm goto statement
90 | __label_warn_on:
| ^
test.c:55:2: note: jump enters a statement expression
55 | ({
| ^
2 warnings and 2 errors generated.
The second is a simpler one from `cvise`, which should convey the same idea.
void kernfs_enable_ns() {
({
__label__ __label_warn_on;
asm goto("" : : : : __label_warn_on);
__label_warn_on:;
});
({
__label__ __label_warn_on;
asm goto("" : : : : __label_warn_on);
__label_warn_on:;
});
}
$ ../install/llvm-good/bin/clang -c -o /dev/null asm-offsets.i
$ ../install/llvm-bad/bin/clang -c -o /dev/null asm-offsets.i
asm-offsets.i:4:5: error: cannot jump from this asm goto statement to one of its possible targets
4 | asm goto("" : : : : __label_warn_on);
| ^
asm-offsets.i:11:1: note: possible target of asm goto statement
11 | __label_warn_on:;
| ^
asm-offsets.i:8:3: note: jump enters a statement expression
8 | ({
| ^
asm-offsets.i:10:5: error: cannot jump from this asm goto statement to one of its possible targets
10 | asm goto("" : : : : __label_warn_on);
| ^
asm-offsets.i:5:1: note: possible target of asm goto statement
5 | __label_warn_on:;
| ^
asm-offsets.i:2:3: note: jump enters a statement expression
2 | ({
| ^
2 errors generated.
GCC 13.1.0 has no issues with either of these test cases.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D154696/new/
https://reviews.llvm.org/D154696
More information about the cfe-commits
mailing list