[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