Skip to content

Conversation

@yonghong-song
Copy link
Contributor

@yonghong-song yonghong-song commented Jun 5, 2025

Ihor Solodrai reported a case ([1]) where gcc reports an error but clang
ignores that error and proceeds to generate incorrect code. More
specifically, the problematic code looks like:

  if r1 == 0xcafefeeddeadbeef goto <label>

Here, 0xcafefeeddeadbeef needs to be encoded in a 32-bit imm field
of the insns and the 32-bit imm allows sign extenstion to 64-bit imm.
Obviously, 0xcafefeeddeadbeef cannot encode properly.

The compilation failed for gcc with the following error:

  Error: immediate out of range, shall fit in 32 bits

Given a 64-bit imm value, converting to the proper 32-bit imm value
must satisfy the following 64-bit patterns:

  00000000 00000000 00000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  11111111 11111111 11111111 11111111 1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

So if the top 32-bits is 0 or the top 33-bits is 0x1ffffffff, then the 64-bit imm
value can be truncated into proper 32-bit imm. Otherwise, a warning
message, the same as gcc, will be issued. If -Werror is enabled during
compilation, the warning will turn into an error.

[1] https://lore.kernel.org/bpf/[email protected]/

@yonghong-song yonghong-song requested review from 4ast and eddyz87 June 5, 2025 15:16
@yonghong-song
Copy link
Contributor Author

cc @jemarch

@github-actions
Copy link

github-actions bot commented Jun 5, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@yonghong-song yonghong-song force-pushed the fix-invalid-insn branch 2 times, most recently from 0ba6601 to 17df3a8 Compare June 5, 2025 15:28
Copy link
Contributor

@eddyz87 eddyz87 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but what is the conclusion of the upstream discussion? should the error be reproted for Imm > UINT_MAX or for Imm > INT_MAX? I think the latter makes sense, as you suggested upsteream.

@yonghong-song
Copy link
Contributor Author

LGTM, but what is the conclusion of the upstream discussion? should the error be reproted for Imm > UINT_MAX or for Imm > INT_MAX? I think the latter makes sense, as you suggested upsteream.

Yes, I do prefer Imm > INT_MAX. But I will emit warning instead of error to maintain some kind of backward compatibility.

@yonghong-song yonghong-song force-pushed the fix-invalid-insn branch 2 times, most recently from 474eb57 to 5148d25 Compare June 10, 2025 05:52
@yonghong-song yonghong-song changed the title [BPF] Report an error if comparison imm operand cannot fit in 32bit [BPF] Report warning for some insn imm requiring int range in inline asm Jun 10, 2025
@eddyz87
Copy link
Contributor

eddyz87 commented Jun 10, 2025

There are quite a few kernel selftests failing to build because of the -Werror:

progs/dummy_st_ops_success.c
progs/dynptr_fail.c
progs/iters.c
progs/verifier_and.c
progs/verifier_array_access.c
progs/verifier_bounds.c
progs/verifier_direct_packet_access.c
progs/verifier_ldsx.c
progs/verifier_masking.c
progs/verifier_movsx.c
progs/verifier_or_jmp32_k.c
progs/verifier_raw_stack.c
progs/verifier_search_pruning.c
progs/verifier_spill_fill.c
progs/verifier_stack_ptr.c
progs/verifier_subreg.c
progs/verifier_unpriv.c

But all seem to be legit warnings for statements like: r1 = 0xffffffff.

@yonghong-song
Copy link
Contributor Author

But all seem to be legit warnings for statements like: r1 = 0xffffffff.

Right, this one definitely legit warnings.

@yonghong-song yonghong-song changed the title [BPF] Report warning for some insn imm requiring int range in inline asm [BPF] Report warning for some insn imm requiring valid range in inline asm Jun 12, 2025
kernel-patches-daemon-bpf-rc bot pushed a commit to kernel-patches/bpf-rc that referenced this pull request Jun 12, 2025
In one of upstream thread ([1]), there is a discussion about
the below inline asm code:

  if r1 == 0xdeadbeef goto +2;
  ...

In actual llvm backend, the above 0xdeadbeef will actually do
sign extension to 64bit value and then compare to register r1.

But the code itself does not imply the above semantics. It looks
like the comparision is between r1 and 0xdeadbeef. For example,
let us at a simple C code:
  $ cat t1.c
  int foo(long a) { return a == 0xdeadbeef ? 2 : 3; }
  $ clang --target=bpf -O2 -c t1.c && llvm-objdump -d t1.o
    ...
    w0 = 0x2
    r2 = 0xdeadbeef ll
    if r1 == r2 goto +0x1
    w0 = 0x3
    exit
It does try to compare r1 and 0xdeadbeef.

To address the above confusing inline asm issue, llvm backend ([2])
added some range checking for such insns and beyond. For the above
insn asm, the warning like below
  warning: immediate out of range, shall fit in int range
will be issued. If -Werror is in the compilation flags, the
error will be issued.

To avoid the above warning/error, the afore-mentioned inline asm
should be rewritten to

  if r1 == -559038737 goto +2;
  ...

Fix a few selftest cases like the above based on insn range checking
requirement in [2].

  [1] https://lore.kernel.org/bpf/[email protected]/
  [2] llvm/llvm-project#142989

Signed-off-by: Yonghong Song <[email protected]>
intel-lab-lkp pushed a commit to intel-lab-lkp/linux that referenced this pull request Jun 12, 2025
In one of upstream thread ([1]), there is a discussion about
the below inline asm code:

  if r1 == 0xdeadbeef goto +2;
  ...

In actual llvm backend, the above 0xdeadbeef will actually do
sign extension to 64bit value and then compare to register r1.

But the code itself does not imply the above semantics. It looks
like the comparision is between r1 and 0xdeadbeef. For example,
let us at a simple C code:
  $ cat t1.c
  int foo(long a) { return a == 0xdeadbeef ? 2 : 3; }
  $ clang --target=bpf -O2 -c t1.c && llvm-objdump -d t1.o
    ...
    w0 = 0x2
    r2 = 0xdeadbeef ll
    if r1 == r2 goto +0x1
    w0 = 0x3
    exit
It does try to compare r1 and 0xdeadbeef.

To address the above confusing inline asm issue, llvm backend ([2])
added some range checking for such insns and beyond. For the above
insn asm, the warning like below
  warning: immediate out of range, shall fit in int range
will be issued. If -Werror is in the compilation flags, the
error will be issued.

To avoid the above warning/error, the afore-mentioned inline asm
should be rewritten to

  if r1 == -559038737 goto +2;
  ...

Fix a few selftest cases like the above based on insn range checking
requirement in [2].

  [1] https://lore.kernel.org/bpf/[email protected]/
  [2] llvm/llvm-project#142989

Signed-off-by: Yonghong Song <[email protected]>
kernel-patches-daemon-bpf bot pushed a commit to kernel-patches/bpf that referenced this pull request Jun 12, 2025
In one of upstream thread ([1]), there is a discussion about
the below inline asm code:

  if r1 == 0xdeadbeef goto +2;
  ...

In actual llvm backend, the above 0xdeadbeef will actually do
sign extension to 64bit value and then compare to register r1.

But the code itself does not imply the above semantics. It looks
like the comparision is between r1 and 0xdeadbeef. For example,
let us at a simple C code:
  $ cat t1.c
  int foo(long a) { return a == 0xdeadbeef ? 2 : 3; }
  $ clang --target=bpf -O2 -c t1.c && llvm-objdump -d t1.o
    ...
    w0 = 0x2
    r2 = 0xdeadbeef ll
    if r1 == r2 goto +0x1
    w0 = 0x3
    exit
It does try to compare r1 and 0xdeadbeef.

To address the above confusing inline asm issue, llvm backend ([2])
added some range checking for such insns and beyond. For the above
insn asm, the warning like below
  warning: immediate out of range, shall fit in int range
will be issued. If -Werror is in the compilation flags, the
error will be issued.

To avoid the above warning/error, the afore-mentioned inline asm
should be rewritten to

  if r1 == -559038737 goto +2;
  ...

Fix a few selftest cases like the above based on insn range checking
requirement in [2].

  [1] https://lore.kernel.org/bpf/[email protected]/
  [2] llvm/llvm-project#142989

Signed-off-by: Yonghong Song <[email protected]>
kernel-patches-daemon-bpf bot pushed a commit to kernel-patches/bpf that referenced this pull request Jun 12, 2025
In one of upstream thread ([1]), there is a discussion about
the below inline asm code:

  if r1 == 0xdeadbeef goto +2;
  ...

In actual llvm backend, the above 0xdeadbeef will actually do
sign extension to 64bit value and then compare to register r1.

But the code itself does not imply the above semantics. It looks
like the comparision is between r1 and 0xdeadbeef. For example,
let us at a simple C code:
  $ cat t1.c
  int foo(long a) { return a == 0xdeadbeef ? 2 : 3; }
  $ clang --target=bpf -O2 -c t1.c && llvm-objdump -d t1.o
    ...
    w0 = 0x2
    r2 = 0xdeadbeef ll
    if r1 == r2 goto +0x1
    w0 = 0x3
    exit
It does try to compare r1 and 0xdeadbeef.

To address the above confusing inline asm issue, llvm backend ([2])
added some range checking for such insns and beyond. For the above
insn asm, the warning like below
  warning: immediate out of range, shall fit in int range
will be issued. If -Werror is in the compilation flags, the
error will be issued.

To avoid the above warning/error, the afore-mentioned inline asm
should be rewritten to

  if r1 == -559038737 goto +2;
  ...

Fix a few selftest cases like the above based on insn range checking
requirement in [2].

  [1] https://lore.kernel.org/bpf/[email protected]/
  [2] llvm/llvm-project#142989

Signed-off-by: Yonghong Song <[email protected]>
kernel-patches-daemon-bpf-rc bot pushed a commit to kernel-patches/bpf-rc that referenced this pull request Jun 12, 2025
In one of upstream thread ([1]), there is a discussion about
the below inline asm code:

  if r1 == 0xdeadbeef goto +2;
  ...

In actual llvm backend, the above 0xdeadbeef will actually do
sign extension to 64bit value and then compare to register r1.

But the code itself does not imply the above semantics. It looks
like the comparision is between r1 and 0xdeadbeef. For example,
let us at a simple C code:
  $ cat t1.c
  int foo(long a) { return a == 0xdeadbeef ? 2 : 3; }
  $ clang --target=bpf -O2 -c t1.c && llvm-objdump -d t1.o
    ...
    w0 = 0x2
    r2 = 0xdeadbeef ll
    if r1 == r2 goto +0x1
    w0 = 0x3
    exit
It does try to compare r1 and 0xdeadbeef.

To address the above confusing inline asm issue, llvm backend ([2])
added some range checking for such insns and beyond. For the above
insn asm, the warning like below
  warning: immediate out of range, shall fit in int range
will be issued. If -Werror is in the compilation flags, the
error will be issued.

To avoid the above warning/error, the afore-mentioned inline asm
should be rewritten to

  if r1 == -559038737 goto +2;
  ...

Fix a few selftest cases like the above based on insn range checking
requirement in [2].

  [1] https://lore.kernel.org/bpf/[email protected]/
  [2] llvm/llvm-project#142989

Signed-off-by: Yonghong Song <[email protected]>
@eddyz87
Copy link
Contributor

eddyz87 commented Jun 12, 2025

Latest changes lgtm.
However, on a second thought, maybe Imm < INT_MIN || Imm > UINT_MAX makes more sense in the end.
E.g. corresponding selftest change is an unnecessary obfuscation:

--- a/tools/testing/selftests/bpf/progs/verifier_and.c
+++ b/tools/testing/selftests/bpf/progs/verifier_and.c
@@ -99,7 +99,7 @@ __naked void known_subreg_with_unknown_reg(void)
 	call %[bpf_get_prandom_u32];			\
 	r0 <<= 32;					\
 	r0 += 1;					\
-	r0 &= 0xFFFF1234;				\
+	r0 &= -60876;					\

kernel-patches-daemon-bpf-rc bot pushed a commit to kernel-patches/bpf-rc that referenced this pull request Jun 12, 2025
In one of upstream thread ([1]), there is a discussion about
the below inline asm code:

  if r1 == 0xdeadbeef goto +2;
  ...

In actual llvm backend, the above 0xdeadbeef will actually do
sign extension to 64bit value and then compare to register r1.

But the code itself does not imply the above semantics. It looks
like the comparision is between r1 and 0xdeadbeef. For example,
let us at a simple C code:
  $ cat t1.c
  int foo(long a) { return a == 0xdeadbeef ? 2 : 3; }
  $ clang --target=bpf -O2 -c t1.c && llvm-objdump -d t1.o
    ...
    w0 = 0x2
    r2 = 0xdeadbeef ll
    if r1 == r2 goto +0x1
    w0 = 0x3
    exit
It does try to compare r1 and 0xdeadbeef.

To address the above confusing inline asm issue, llvm backend ([2])
added some range checking for such insns and beyond. For the above
insn asm, the warning like below
  warning: immediate out of range, shall fit in int range
will be issued. If -Werror is in the compilation flags, the
error will be issued.

To avoid the above warning/error, the afore-mentioned inline asm
should be rewritten to

  if r1 == -559038737 goto +2;
  ...

Fix a few selftest cases like the above based on insn range checking
requirement in [2].

  [1] https://lore.kernel.org/bpf/[email protected]/
  [2] llvm/llvm-project#142989

Signed-off-by: Yonghong Song <[email protected]>
kernel-patches-daemon-bpf bot pushed a commit to kernel-patches/bpf that referenced this pull request Jun 12, 2025
In one of upstream thread ([1]), there is a discussion about
the below inline asm code:

  if r1 == 0xdeadbeef goto +2;
  ...

In actual llvm backend, the above 0xdeadbeef will actually do
sign extension to 64bit value and then compare to register r1.

But the code itself does not imply the above semantics. It looks
like the comparision is between r1 and 0xdeadbeef. For example,
let us at a simple C code:
  $ cat t1.c
  int foo(long a) { return a == 0xdeadbeef ? 2 : 3; }
  $ clang --target=bpf -O2 -c t1.c && llvm-objdump -d t1.o
    ...
    w0 = 0x2
    r2 = 0xdeadbeef ll
    if r1 == r2 goto +0x1
    w0 = 0x3
    exit
It does try to compare r1 and 0xdeadbeef.

To address the above confusing inline asm issue, llvm backend ([2])
added some range checking for such insns and beyond. For the above
insn asm, the warning like below
  warning: immediate out of range, shall fit in int range
will be issued. If -Werror is in the compilation flags, the
error will be issued.

To avoid the above warning/error, the afore-mentioned inline asm
should be rewritten to

  if r1 == -559038737 goto +2;
  ...

Fix a few selftest cases like the above based on insn range checking
requirement in [2].

  [1] https://lore.kernel.org/bpf/[email protected]/
  [2] llvm/llvm-project#142989

Signed-off-by: Yonghong Song <[email protected]>
kernel-patches-daemon-bpf-rc bot pushed a commit to kernel-patches/bpf-rc that referenced this pull request Jun 12, 2025
In one of upstream thread ([1]), there is a discussion about
the below inline asm code:

  if r1 == 0xdeadbeef goto +2;
  ...

In actual llvm backend, the above 0xdeadbeef will actually do
sign extension to 64bit value and then compare to register r1.

But the code itself does not imply the above semantics. It looks
like the comparision is between r1 and 0xdeadbeef. For example,
let us at a simple C code:
  $ cat t1.c
  int foo(long a) { return a == 0xdeadbeef ? 2 : 3; }
  $ clang --target=bpf -O2 -c t1.c && llvm-objdump -d t1.o
    ...
    w0 = 0x2
    r2 = 0xdeadbeef ll
    if r1 == r2 goto +0x1
    w0 = 0x3
    exit
It does try to compare r1 and 0xdeadbeef.

To address the above confusing inline asm issue, llvm backend ([2])
added some range checking for such insns and beyond. For the above
insn asm, the warning like below
  warning: immediate out of range, shall fit in int range
will be issued. If -Werror is in the compilation flags, the
error will be issued.

To avoid the above warning/error, the afore-mentioned inline asm
should be rewritten to

  if r1 == -559038737 goto +2;
  ...

Fix a few selftest cases like the above based on insn range checking
requirement in [2].

  [1] https://lore.kernel.org/bpf/[email protected]/
  [2] llvm/llvm-project#142989

Signed-off-by: Yonghong Song <[email protected]>
kernel-patches-daemon-bpf bot pushed a commit to kernel-patches/bpf that referenced this pull request Jun 13, 2025
In one of upstream thread ([1]), there is a discussion about
the below inline asm code:

  if r1 == 0xdeadbeef goto +2;
  ...

In actual llvm backend, the above 0xdeadbeef will actually do
sign extension to 64bit value and then compare to register r1.

But the code itself does not imply the above semantics. It looks
like the comparision is between r1 and 0xdeadbeef. For example,
let us at a simple C code:
  $ cat t1.c
  int foo(long a) { return a == 0xdeadbeef ? 2 : 3; }
  $ clang --target=bpf -O2 -c t1.c && llvm-objdump -d t1.o
    ...
    w0 = 0x2
    r2 = 0xdeadbeef ll
    if r1 == r2 goto +0x1
    w0 = 0x3
    exit
It does try to compare r1 and 0xdeadbeef.

To address the above confusing inline asm issue, llvm backend ([2])
added some range checking for such insns and beyond. For the above
insn asm, the warning like below
  warning: immediate out of range, shall fit in int range
will be issued. If -Werror is in the compilation flags, the
error will be issued.

To avoid the above warning/error, the afore-mentioned inline asm
should be rewritten to

  if r1 == -559038737 goto +2;
  ...

Fix a few selftest cases like the above based on insn range checking
requirement in [2].

  [1] https://lore.kernel.org/bpf/[email protected]/
  [2] llvm/llvm-project#142989

Signed-off-by: Yonghong Song <[email protected]>
Ihor Solodrai reported a case ([1]) where gcc reports an error but clang
ignores that error and proceeds to generate incorrect code. More
specifically, the problematic code looks like:
  if r1 == 0xcafefeeddeadbeef goto <label>

Here, 0xcafefeeddeadbeef needs to be encoded in a 32-bit imm field
of the insns and the 32-bit imm allows sign extenstion to 64-bit imm.
Obviously, 0xcafefeeddeadbeef cannot encode properly.

The compilation failed for gcc with the following error:
  Error: immediate out of range, shall fit in 32 bits

Given a 64-bit imm value, converting to the proper 32-bit imm value
must satisfy the following 64-bit patterns:
  00000000 00000000 00000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  11111111 11111111 11111111 11111111 1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

So if the top 32-bits is 0 or the top 33-bits is 0x1ffffffff, then the 64-bit imm
value can be truncated into proper 32-bit imm. Otherwise, a warning
message, the same as gcc will be issued. If -Werror is enabled during
compilation, the warning will turn into an error.

  [1] https://lore.kernel.org/bpf/[email protected]/
@yonghong-song yonghong-song changed the title [BPF] Report warning for some insn imm requiring valid range in inline asm [BPF] Report an warning if certain insn imm operand cannot fit in 32bit Jun 13, 2025
@yonghong-song yonghong-song merged commit 2f1e6eb into llvm:main Jun 13, 2025
7 checks passed
tomtor pushed a commit to tomtor/llvm-project that referenced this pull request Jun 14, 2025
…it (llvm#142989)

Ihor Solodrai reported a case ([1]) where gcc reports an error but clang
ignores that error and proceeds to generate incorrect code. More
specifically, the problematic code looks like:
   if r1 == 0xcafefeeddeadbeef goto <label>

Here, 0xcafefeeddeadbeef needs to be encoded in a 32-bit imm field
of the insns and the 32-bit imm allows sign extenstion to 64-bit imm.
Obviously, 0xcafefeeddeadbeef cannot encode properly.

The compilation failed for gcc with the following error:
  Error: immediate out of range, shall fit in 32 bits

Given a 64-bit imm value, converting to the proper 32-bit imm value
must satisfy the following 64-bit patterns:
  00000000 00000000 00000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  11111111 11111111 11111111 11111111 1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

So if the top 32-bits is 0 or the top 33-bits is 0x1ffffffff, then the 64-bit imm
value can be truncated into proper 32-bit imm. Otherwise, a warning
message, the same as gcc, will be issued. If -Werror is enabled during
compilation, the warning will turn into an error.

[1] https://lore.kernel.org/bpf/[email protected]/
akuhlens pushed a commit to akuhlens/llvm-project that referenced this pull request Jun 24, 2025
…it (llvm#142989)

Ihor Solodrai reported a case ([1]) where gcc reports an error but clang
ignores that error and proceeds to generate incorrect code. More
specifically, the problematic code looks like:
   if r1 == 0xcafefeeddeadbeef goto <label>

Here, 0xcafefeeddeadbeef needs to be encoded in a 32-bit imm field
of the insns and the 32-bit imm allows sign extenstion to 64-bit imm.
Obviously, 0xcafefeeddeadbeef cannot encode properly.

The compilation failed for gcc with the following error:
  Error: immediate out of range, shall fit in 32 bits

Given a 64-bit imm value, converting to the proper 32-bit imm value
must satisfy the following 64-bit patterns:
  00000000 00000000 00000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  11111111 11111111 11111111 11111111 1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

So if the top 32-bits is 0 or the top 33-bits is 0x1ffffffff, then the 64-bit imm
value can be truncated into proper 32-bit imm. Otherwise, a warning
message, the same as gcc, will be issued. If -Werror is enabled during
compilation, the warning will turn into an error.

[1] https://lore.kernel.org/bpf/[email protected]/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants