Skip to content

Commit f63d143

Browse files
authored
Codegen unimplemented for fat pointer operations for now (#1084)
This mitigates #327 and #675
1 parent b8055fc commit f63d143

File tree

7 files changed

+224
-1
lines changed

7 files changed

+224
-1
lines changed

kani-compiler/src/codegen_cprover_gotoc/codegen/rvalue.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,23 @@ impl<'tcx> GotocCtx<'tcx> {
4242
}
4343
}
4444

45+
/// This function codegen comparison for fat pointers.
46+
/// We currently don't support this. See issue #327 for more information.
47+
fn codegen_comparison_fat_ptr(
48+
&mut self,
49+
op: &BinOp,
50+
left: &Operand<'tcx>,
51+
right: &Operand<'tcx>,
52+
) -> Expr {
53+
debug!(?op, ?left, ?right, "codegen_comparison_fat_ptr");
54+
self.codegen_unimplemented(
55+
&format!("Fat pointer comparison '{:?}'", op),
56+
Type::Bool,
57+
Location::None,
58+
"https://github.com/model-checking/kani/issues/327",
59+
)
60+
}
61+
4562
fn codegen_unchecked_scalar_binop(
4663
&mut self,
4764
op: &BinOp,
@@ -311,7 +328,11 @@ impl<'tcx> GotocCtx<'tcx> {
311328
self.codegen_unchecked_scalar_binop(op, e1, e2)
312329
}
313330
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
314-
self.codegen_comparison(op, e1, e2)
331+
if self.is_ref_of_unsized(self.operand_ty(e1)) {
332+
self.codegen_comparison_fat_ptr(op, e1, e2)
333+
} else {
334+
self.codegen_comparison(op, e1, e2)
335+
}
315336
}
316337
// https://doc.rust-lang.org/std/primitive.pointer.html#method.offset
317338
BinOp::Offset => {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
[package]
4+
name = "check_percent_encode"
5+
version = "0.1.0"
6+
edition = "2021"
7+
8+
9+
[dependencies]
10+
percent-encoding = "2.1.0"
11+
12+
[package.metadata.kani.flags]
13+
only-codegen = true
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
5+
6+
#[kani::proof]
7+
pub fn check_encoding() {
8+
let hello = utf8_percent_encode("hello world", NON_ALPHANUMERIC);
9+
assert_eq!(hello.to_string(), "hello%20world");
10+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Checking harness check_slice_ptr...
2+
Status: FAILURE\
3+
Description: "Fat pointer comparison 'Lt' is not currently supported by Kani. Please post your example at https://github.com/model-checking/kani/issues/327"
4+
5+
Status: UNDETERMINED\
6+
Description: "Fat pointer comparison 'Le' is not currently supported by Kani. Please post your example at https://github.com/model-checking/kani/issues/327"
7+
8+
Status: UNDETERMINED\
9+
Description: "Fat pointer comparison 'Gt' is not currently supported by Kani. Please post your example at https://github.com/model-checking/kani/issues/327"
10+
11+
Status: UNDETERMINED\
12+
Description: "Fat pointer comparison 'Ge' is not currently supported by Kani. Please post your example at https://github.com/model-checking/kani/issues/327"
13+
14+
Status: UNDETERMINED\
15+
Description: "Fat pointer comparison 'Ne' is not currently supported by Kani. Please post your example at https://github.com/model-checking/kani/issues/327"
16+
17+
Status: UNDETERMINED\
18+
Description: "Fat pointer comparison 'Eq' is not currently supported by Kani. Please post your example at https://github.com/model-checking/kani/issues/327"
19+
20+
Failed Checks: Fat pointer comparison 'Lt' is not currently supported by Kani. Please post your example at https://github.com/model-checking/kani/issues/327
21+
22+
23+
Checking harness check_dyn_ptr...
24+
25+
Failed Checks: Fat pointer comparison 'Lt' is not currently supported by Kani. Please post your example at https://github.com/model-checking/kani/issues/327
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
//! Test relation comparison of fat pointers to slices.
5+
use std::cmp::*;
6+
7+
/// Check comparison operators for two different elements.
8+
fn compare<T: ?Sized>(smaller: *const T, bigger: *const T) {
9+
// Check relation operations that should return true.
10+
assert!(smaller < bigger);
11+
assert!(smaller <= bigger);
12+
assert!(bigger > smaller);
13+
assert!(bigger >= smaller);
14+
assert!(bigger != smaller);
15+
assert!(!(bigger == smaller));
16+
}
17+
18+
#[kani::proof]
19+
fn check_slice_ptr() {
20+
let array = [[0u8, 2]; 10];
21+
let first_ptr: *const [u8] = &array[0];
22+
let second_ptr: *const [u8] = &array[5];
23+
24+
compare(first_ptr, second_ptr);
25+
}
26+
27+
trait Dummy {}
28+
impl Dummy for u8 {}
29+
30+
#[kani::proof]
31+
fn check_dyn_ptr() {
32+
let array = [0u8; 10];
33+
let first_ptr: *const dyn Dummy = &array[0];
34+
let second_ptr: *const dyn Dummy = &array[5];
35+
36+
compare(first_ptr, second_ptr);
37+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
//! Test relation comparison of fat pointers to slices.
5+
use std::cmp::*;
6+
7+
/// Check comparison operators for two different elements.
8+
fn compare_diff<T: ?Sized>(smaller: *const T, bigger: *const T) {
9+
// Check Ord::cmp().
10+
assert_eq!(smaller.cmp(&bigger), Ordering::Less);
11+
assert_eq!(bigger.cmp(&smaller), Ordering::Greater);
12+
13+
// Check relation operations that should return true.
14+
assert!(smaller < bigger);
15+
assert!(smaller <= bigger);
16+
assert!(bigger > smaller);
17+
assert!(bigger >= smaller);
18+
assert!(bigger != smaller);
19+
20+
// Check relation operations that should return false.
21+
assert!(!(smaller > bigger));
22+
assert!(!(smaller >= bigger));
23+
assert!(!(bigger <= smaller));
24+
assert!(!(bigger < smaller));
25+
assert!(!(bigger == smaller));
26+
assert!(!(std::ptr::eq(bigger, smaller)));
27+
28+
// Check Ord::{max, min}.
29+
assert_eq!(smaller.min(bigger), smaller);
30+
assert_eq!(smaller.max(bigger), bigger);
31+
assert_eq!(bigger.min(smaller), smaller);
32+
assert_eq!(bigger.max(smaller), bigger);
33+
}
34+
35+
/// Check comparison operators for the same object.
36+
fn compare_equal<T: ?Sized>(object: *const T) {
37+
// Check Ord::cmp().
38+
assert_eq!(object.cmp(&object), Ordering::Equal);
39+
40+
// Check relation operations that should return true.
41+
assert!(object <= object);
42+
assert!(object >= object);
43+
assert!(object == object);
44+
45+
// Check relation operations that should return false.
46+
assert!(!(object > object));
47+
assert!(!(object < object));
48+
assert!(!(object != object));
49+
50+
// Check Ord::{max, min}.
51+
assert_eq!(object.min(object), object);
52+
assert_eq!(object.max(object), object);
53+
}
54+
55+
/// Check clamp operation.
56+
fn check_clamp<T: ?Sized>(object: *const T, smaller: *const T, bigger: *const T) {
57+
assert_eq!(object.clamp(smaller, bigger), object);
58+
assert_eq!(object.clamp(smaller, object), object);
59+
assert_eq!(object.clamp(object, bigger), object);
60+
61+
assert_eq!(object.clamp(bigger, bigger), bigger);
62+
assert_eq!(object.clamp(smaller, smaller), smaller);
63+
}
64+
65+
#[cfg_attr(kani, kani::proof)]
66+
fn check_thin_ptr() {
67+
let array = [0u8; 10];
68+
let first_ptr: *const u8 = &array[0];
69+
let second_ptr: *const u8 = &array[5];
70+
71+
compare_diff(first_ptr, second_ptr);
72+
compare_equal(first_ptr);
73+
check_clamp(&array[5], &array[0], &array[9]);
74+
}
75+
76+
#[cfg_attr(kani, kani::proof)]
77+
fn check_slice_ptr() {
78+
let array = [[0u8, 2]; 10];
79+
let first_ptr: *const [u8] = &array[0];
80+
let second_ptr: *const [u8] = &array[5];
81+
82+
compare_diff(first_ptr, second_ptr);
83+
compare_equal(first_ptr);
84+
check_clamp::<[u8]>(&array[5], &array[0], &array[9]);
85+
}
86+
87+
trait Dummy {}
88+
impl Dummy for u8 {}
89+
90+
#[cfg_attr(kani, kani::proof)]
91+
fn check_dyn_ptr() {
92+
let array = [0u8; 10];
93+
let first_ptr: *const dyn Dummy = &array[0];
94+
let second_ptr: *const dyn Dummy = &array[5];
95+
96+
compare_diff(first_ptr, second_ptr);
97+
compare_equal(first_ptr);
98+
check_clamp::<dyn Dummy>(&array[5], &array[0], &array[9]);
99+
}
100+
101+
// Allow us to run usign rustc.
102+
fn main() {
103+
check_thin_ptr();
104+
check_slice_ptr();
105+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
#[kani::proof]
5+
fn check_thin_ptr() {
6+
let array = [0, 1, 2, 3, 4, 5, 6];
7+
let second_ptr: *const i32 = &array[3];
8+
unsafe {
9+
let before = second_ptr.sub(1);
10+
assert_eq!(*before, 2);
11+
}
12+
}

0 commit comments

Comments
 (0)