Skip to content

Commit eed3366

Browse files
authored
[llubi] Add support for poison-generating/UB-implying annotations (llvm#195339)
This patch adds support for poison-generating/UB-implying annotations, including: 1. Parameter/retval attributes on function declarations and call sites (range/nofpclass/align/nonnull/noundef/dereferenceable[_or_null]). 2. Metadata (!range/!nofpclass/!align/!nonnull/!noundef/!dereferenceable[_or_null]) 3. Assume operand bundles (nonnull/align/dereferenceable[_or_null]) I put all of them into a single patch as they share most of the common logic. Note that there are two todos to reach the full support: 1. Load with `!noundef` metadata doesn't check undef bits for now. 2. !dereferenceable[_or_null] on load (and inttoptr) are not tested by this patch, as it needs the provenance support (llvm#185977). But it should be fine as they are tested by metadata on call sites.
1 parent 0b65233 commit eed3366

24 files changed

Lines changed: 1052 additions & 16 deletions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
2+
; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
3+
4+
define void @main() {
5+
%alloc = alloca i32
6+
call void @llvm.assume(i1 true) ["align"(ptr null, i128 18446744073709551617)]
7+
call void @llvm.assume(i1 true) ["align"(ptr %alloc, i128 18446744073709551616)]
8+
ret void
9+
}
10+
; CHECK: Entering function: main
11+
; CHECK-NEXT: %alloc = alloca i32, align 4 => ptr 0x8 [alloc]
12+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr null, i128 18446744073709551617) ]
13+
; CHECK-NEXT: Stacktrace:
14+
; CHECK-NEXT: #0 call void @llvm.assume(i1 true) [ "align"(ptr %alloc, i128 18446744073709551616) ] at @main
15+
; CHECK-NEXT: Immediate UB detected: The pointer ptr 0x8 [alloc] violates align(18446744073709551616) assumption.
16+
; CHECK-NEXT: error: Execution of function 'main' failed.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
2+
; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
3+
4+
define void @main() {
5+
%alloc = alloca i32
6+
call void @llvm.assume(i1 true) ["align"(ptr %alloc, i32 2048)]
7+
ret void
8+
}
9+
; CHECK: Entering function: main
10+
; CHECK-NEXT: %alloc = alloca i32, align 4 => ptr 0x8 [alloc]
11+
; CHECK-NEXT: Stacktrace:
12+
; CHECK-NEXT: #0 call void @llvm.assume(i1 true) [ "align"(ptr %alloc, i32 2048) ] at @main
13+
; CHECK-NEXT: Immediate UB detected: The pointer ptr 0x8 [alloc] violates align(2048) assumption.
14+
; CHECK-NEXT: error: Execution of function 'main' failed.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
2+
; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
3+
4+
target datalayout = "po1:64:64"
5+
6+
define void @main() {
7+
call void @llvm.assume(i1 true) ["align"(ptr addrspace(1) null, i32 2048)]
8+
ret void
9+
}
10+
; CHECK: Entering function: main
11+
; CHECK-NEXT: Stacktrace:
12+
; CHECK-NEXT: #0 call void @llvm.assume(i1 true) [ "align"(ptr addrspace(1) null, i32 2048) ] at @main
13+
; CHECK-NEXT: Immediate UB detected: The pointer ptr 0xFFFFFFFFFFFFFFFF [dangling] violates align(2048) assumption.
14+
; CHECK-NEXT: error: Execution of function 'main' failed.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
2+
; RUN: sed 's/dereferenceable/dereferenceable_or_null/g' %s | not llubi --verbose 2>&1 | FileCheck %s
3+
4+
define void @main() {
5+
%alloc = alloca i32
6+
call void @llvm.assume(i1 true) ["dereferenceable"(ptr %alloc, i32 2048)]
7+
ret void
8+
}
9+
; CHECK: Entering function: main
10+
; CHECK-NEXT: %alloc = alloca i32, align 4 => ptr 0x8 [alloc]
11+
; CHECK-NEXT: Stacktrace:
12+
; CHECK-NEXT: #0 call void @llvm.assume(i1 true) [ "dereferenceable{{(_or_null)?}}"(ptr %alloc, i32 2048) ] at @main
13+
; CHECK-NEXT: Immediate UB detected: The pointer ptr 0x8 [alloc] violates dereferenceable{{(_or_null)?}}(2048) assumption.
14+
; CHECK-NEXT: error: Execution of function 'main' failed.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
2+
; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
3+
4+
define void @main() {
5+
call void @llvm.assume(i1 true) ["nonnull"(ptr null)]
6+
ret void
7+
}
8+
; CHECK: Entering function: main
9+
; CHECK-NEXT: Stacktrace:
10+
; CHECK-NEXT: #0 call void @llvm.assume(i1 true) [ "nonnull"(ptr null) ] at @main
11+
; CHECK-NEXT: Immediate UB detected: The pointer ptr 0x0 [dangling] violates nonnull assumption.
12+
; CHECK-NEXT: error: Execution of function 'main' failed.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
2+
; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
3+
4+
target datalayout = "po1:64:64"
5+
6+
define void @main() {
7+
%storage = alloca ptr
8+
store i64 -1, ptr %storage
9+
%res = load ptr addrspace(1), ptr %storage
10+
call void @llvm.assume(i1 true) ["nonnull"(ptr addrspace(1) %res)]
11+
ret void
12+
}
13+
; CHECK: Entering function: main
14+
; CHECK-NEXT: %storage = alloca ptr, align 8 => ptr 0x8 [storage]
15+
; CHECK-NEXT: store i64 -1, ptr %storage, align 4
16+
; CHECK-NEXT: %res = load ptr addrspace(1), ptr %storage, align 8 => ptr 0xFFFFFFFFFFFFFFFF [dangling]
17+
; CHECK-NEXT: Stacktrace:
18+
; CHECK-NEXT: #0 call void @llvm.assume(i1 true) [ "nonnull"(ptr addrspace(1) %res) ] at @main
19+
; CHECK-NEXT: Immediate UB detected: The pointer ptr 0xFFFFFFFFFFFFFFFF [dangling] violates nonnull assumption.
20+
; CHECK-NEXT: error: Execution of function 'main' failed.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
2+
; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
3+
4+
define void @assume_align_dynamic(ptr %p, i32 %align) {
5+
call void @llvm.assume(i1 true) ["align"(ptr %p, i32 4)]
6+
call void @llvm.assume(i1 true) ["align"(ptr %p, i32 %align)]
7+
call void @llvm.assume(i1 true) ["align"(ptr %p, i32 %align, i32 20)]
8+
ret void
9+
}
10+
11+
define void @main() {
12+
%alloc = alloca i32
13+
call void @llvm.assume(i1 true) ["nonnull"(ptr %alloc)]
14+
call void @llvm.assume(i1 true) ["cold"(), "nonnull"(ptr %alloc), "cold"()]
15+
call void @assume_align_dynamic(ptr %alloc, i32 8)
16+
call void @llvm.assume(i1 true) ["align"(ptr null, i32 17)]
17+
call void @llvm.assume(i1 true) ["align"(ptr null, i32 0)]
18+
call void @llvm.assume(i1 true) ["dereferenceable"(ptr %alloc, i32 4)]
19+
call void @llvm.assume(i1 true) ["dereferenceable"(ptr %alloc, i32 0)]
20+
call void @llvm.assume(i1 true) ["dereferenceable_or_null"(ptr %alloc, i32 4)]
21+
call void @llvm.assume(i1 true) ["dereferenceable_or_null"(ptr null, i32 4)]
22+
call void @llvm.assume(i1 true) ["dereferenceable"(ptr %alloc, i32 4), "dereferenceable_or_null"(ptr %alloc, i32 4), "dereferenceable_or_null"(ptr null, i32 4)]
23+
ret void
24+
}
25+
; CHECK: Entering function: main
26+
; CHECK-NEXT: %alloc = alloca i32, align 4 => ptr 0x8 [alloc]
27+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr %alloc) ]
28+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "cold"(), "nonnull"(ptr %alloc), "cold"() ]
29+
; CHECK-NEXT: Entering function: assume_align_dynamic
30+
; CHECK-NEXT: ptr %p = ptr 0x8 [alloc]
31+
; CHECK-NEXT: i32 %align = i32 8
32+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 4) ]
33+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 %align) ]
34+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 %align, i32 20) ]
35+
; CHECK-NEXT: ret void
36+
; CHECK-NEXT: Exiting function: assume_align_dynamic
37+
; CHECK-NEXT: call void @assume_align_dynamic(ptr %alloc, i32 8)
38+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr null, i32 17) ]
39+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr null, i32 0) ]
40+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %alloc, i32 4) ]
41+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %alloc, i32 0) ]
42+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable_or_null"(ptr %alloc, i32 4) ]
43+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable_or_null"(ptr null, i32 4) ]
44+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %alloc, i32 4), "dereferenceable_or_null"(ptr %alloc, i32 4), "dereferenceable_or_null"(ptr null, i32 4) ]
45+
; CHECK-NEXT: ret void
46+
; CHECK-NEXT: Exiting function: main

llvm/test/tools/llubi/assume_poison.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ define void @main() {
88
; CHECK: Entering function: main
99
; CHECK-NEXT: Stacktrace:
1010
; CHECK-NEXT: #0 call void @llvm.assume(i1 poison) at @main
11-
; CHECK-NEXT: Immediate UB detected: Assume on false or poison condition.
11+
; CHECK-NEXT: Immediate UB detected: The value poison violates noundef attribute.
1212
; CHECK-NEXT: error: Execution of function 'main' failed.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
2+
; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
3+
4+
define void @main() {
5+
call void @llvm.assume(i1 true) ["align"(ptr poison, i32 4)]
6+
ret void
7+
}
8+
; CHECK: Entering function: main
9+
; CHECK-NEXT: Stacktrace:
10+
; CHECK-NEXT: #0 call void @llvm.assume(i1 true) [ "align"(ptr poison, i32 4) ] at @main
11+
; CHECK-NEXT: Immediate UB detected: Assume on poison pointer.
12+
; CHECK-NEXT: error: Execution of function 'main' failed.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
2+
; RUN: sed 's/dereferenceable/dereferenceable_or_null/g' %s | not llubi --verbose 2>&1 | FileCheck %s
3+
4+
define void @callee(ptr dereferenceable(4) %x) {
5+
ret void
6+
}
7+
8+
define void @main() {
9+
%ptr_storage = alloca i64
10+
%p = load ptr, ptr %ptr_storage
11+
call void @callee(ptr %p)
12+
ret void
13+
}
14+
; CHECK: Entering function: main
15+
; CHECK-NEXT: %ptr_storage = alloca i64, align 8 => ptr 0x8 [ptr_storage]
16+
; CHECK-NEXT: %p = load ptr, ptr %ptr_storage, align 8 => ptr 0xE82FEEACEEB98B3E [dangling]
17+
; CHECK-NEXT: Stacktrace:
18+
; CHECK-NEXT: #0 call void @callee(ptr %p) at @main
19+
; CHECK-NEXT: Immediate UB detected: The value ptr 0xE82FEEACEEB98B3E [dangling] violates dereferenceable{{(_or_null)?}}(4) attribute.
20+
; CHECK-NEXT: error: Execution of function 'main' failed.

0 commit comments

Comments
 (0)