Skip to content

Commit 73e449c

Browse files
celinvaladpaco-aws
andauthored
Update rust toolchain to 2022-05-17 (#1209)
* Update rust toolchain to 2022-05-17 Status: Compilation succeeds but regression fails due to new intrinsic. Relevant changes: - rust-lang/rust#95837 - rust-lang/rust#95562 - rust-lang/rust#96883 * Implement new intrinsic ptr_offset_from_unsigned This new intrinsic is used in many different places in the standard library and it was failing some tests for vectors. * Apply suggestions from code review Co-authored-by: Adrian Palacios <[email protected]> * Address PR comments - Fix order of checks. - Improve error message. - Add comments to the new tests. Co-authored-by: Adrian Palacios <[email protected]>
1 parent 96c6b3b commit 73e449c

File tree

13 files changed

+140
-26
lines changed

13 files changed

+140
-26
lines changed

cprover_bindings/src/goto_program/expr.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,13 @@ impl Expr {
12211221
self.lt(typ.zero())
12221222
}
12231223

1224+
/// `self >= 0`
1225+
pub fn is_non_negative(self) -> Self {
1226+
assert!(self.typ.is_numeric());
1227+
let typ = self.typ.clone();
1228+
self.ge(typ.zero())
1229+
}
1230+
12241231
/// `self == 0`
12251232
pub fn is_zero(self) -> Self {
12261233
assert!(self.typ.is_numeric());

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

+15
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,21 @@ impl<'tcx> GotocCtx<'tcx> {
8383
Stmt::assert(cond, property_name, message, loc)
8484
}
8585

86+
pub fn codegen_assert_assume(
87+
&self,
88+
cond: Expr,
89+
property_class: PropertyClass,
90+
message: &str,
91+
loc: Location,
92+
) -> Stmt {
93+
assert!(cond.typ().is_bool());
94+
let property_name = property_class.as_str();
95+
Stmt::block(
96+
vec![Stmt::assert(cond.clone(), property_name, message, loc), Stmt::assume(cond, loc)],
97+
loc,
98+
)
99+
}
100+
86101
pub fn codegen_assert_false(
87102
&self,
88103
property_class: PropertyClass,

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,8 @@ impl<'tcx> GotocCtx<'tcx> {
243243
///
244244
/// Handle all attributes i.e. `#[kani::x]` (which kani_macros translates to `#[kanitool::x]` for us to handle here)
245245
fn handle_kanitool_attributes(&mut self) {
246-
let all_attributes = self.tcx.get_attrs(self.current_fn().instance().def_id());
246+
let all_attributes = self.tcx.get_attrs_unchecked(self.current_fn().instance().def_id());
247247
let (proof_attributes, other_attributes) = partition_kanitool_attributes(all_attributes);
248-
249248
if proof_attributes.is_empty() && !other_attributes.is_empty() {
250249
self.tcx.sess.span_err(
251250
other_attributes[0].1.span,

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

+57-12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use super::typ::pointee_type;
55
use super::PropertyClass;
66
use crate::codegen_cprover_gotoc::GotocCtx;
7-
use cbmc::goto_program::{BuiltinFn, Expr, Location, Stmt, Type};
7+
use cbmc::goto_program::{ArithmeticOverflowResult, BuiltinFn, Expr, Location, Stmt, Type};
88
use rustc_middle::mir::{BasicBlock, Operand, Place};
99
use rustc_middle::ty::layout::LayoutOf;
1010
use rustc_middle::ty::{self, Ty};
@@ -551,6 +551,7 @@ impl<'tcx> GotocCtx<'tcx> {
551551
"ptr_guaranteed_eq" => codegen_ptr_guaranteed_cmp!(eq),
552552
"ptr_guaranteed_ne" => codegen_ptr_guaranteed_cmp!(neq),
553553
"ptr_offset_from" => self.codegen_ptr_offset_from(fargs, p, loc),
554+
"ptr_offset_from_unsigned" => self.codegen_ptr_offset_from_unsigned(fargs, p, loc),
554555
"raw_eq" => self.codegen_intrinsic_raw_eq(instance, fargs, p, loc),
555556
"rintf32" => codegen_unimplemented_intrinsic!(
556557
"https://github.com/model-checking/kani/issues/1025"
@@ -1009,33 +1010,77 @@ impl<'tcx> GotocCtx<'tcx> {
10091010
/// https://doc.rust-lang.org/std/intrinsics/fn.ptr_offset_from.html
10101011
fn codegen_ptr_offset_from(
10111012
&mut self,
1012-
mut fargs: Vec<Expr>,
1013+
fargs: Vec<Expr>,
10131014
p: &Place<'tcx>,
10141015
loc: Location,
10151016
) -> Stmt {
1016-
let dst_ptr = fargs.remove(0);
1017-
let src_ptr = fargs.remove(0);
1018-
1019-
// Compute the offset with standard substraction using `isize`
1020-
let cast_dst_ptr = dst_ptr.clone().cast_to(Type::ssize_t());
1021-
let cast_src_ptr = src_ptr.clone().cast_to(Type::ssize_t());
1022-
let offset = cast_dst_ptr.sub_overflow(cast_src_ptr);
1017+
let (offset_expr, offset_overflow) = self.codegen_ptr_offset_from_expr(fargs);
10231018

10241019
// Check that computing `offset` in bytes would not overflow an `isize`
10251020
// These checks may allow a wrapping-around behavior in CBMC:
10261021
// https://github.com/model-checking/kani/issues/1150
10271022
let overflow_check = self.codegen_assert(
1028-
offset.overflowed.not(),
1023+
offset_overflow.overflowed.not(),
10291024
PropertyClass::ArithmeticOverflow,
10301025
"attempt to compute offset in bytes which would overflow an `isize`",
10311026
loc,
10321027
);
10331028

1034-
// Re-compute the offset with standard substraction (no casts this time)
1035-
let offset_expr = self.codegen_expr_to_place(p, dst_ptr.sub(src_ptr));
1029+
let offset_expr = self.codegen_expr_to_place(p, offset_expr);
10361030
Stmt::block(vec![overflow_check, offset_expr], loc)
10371031
}
10381032

1033+
/// `ptr_offset_from_unsigned` returns the offset between two pointers where the order is known.
1034+
/// The logic is similar to `ptr_offset_from` but the return value is a `usize`.
1035+
/// See https://github.com/rust-lang/rust/issues/95892 for more details
1036+
fn codegen_ptr_offset_from_unsigned(
1037+
&mut self,
1038+
fargs: Vec<Expr>,
1039+
p: &Place<'tcx>,
1040+
loc: Location,
1041+
) -> Stmt {
1042+
let (offset_expr, offset_overflow) = self.codegen_ptr_offset_from_expr(fargs);
1043+
1044+
// Check that computing `offset` in bytes would not overflow an `isize`
1045+
// These checks may allow a wrapping-around behavior in CBMC:
1046+
// https://github.com/model-checking/kani/issues/1150
1047+
let overflow_check = self.codegen_assert_assume(
1048+
offset_overflow.overflowed.not(),
1049+
PropertyClass::ArithmeticOverflow,
1050+
"attempt to compute offset in bytes which would overflow an `isize`",
1051+
loc,
1052+
);
1053+
1054+
let non_negative_check = self.codegen_assert_assume(
1055+
offset_overflow.result.is_non_negative(),
1056+
PropertyClass::KaniCheck,
1057+
"attempt to compute unsigned offset with negative distance",
1058+
loc,
1059+
);
1060+
1061+
let offset_expr = self.codegen_expr_to_place(p, offset_expr.cast_to(Type::size_t()));
1062+
Stmt::block(vec![overflow_check, non_negative_check, offset_expr], loc)
1063+
}
1064+
1065+
/// Both `ptr_offset_from` and `ptr_offset_from_unsigned` return the offset between two pointers.
1066+
/// This function implements the common logic between them.
1067+
fn codegen_ptr_offset_from_expr(
1068+
&mut self,
1069+
mut fargs: Vec<Expr>,
1070+
) -> (Expr, ArithmeticOverflowResult) {
1071+
let dst_ptr = fargs.remove(0);
1072+
let src_ptr = fargs.remove(0);
1073+
1074+
// Compute the offset with standard substraction using `isize`
1075+
let cast_dst_ptr = dst_ptr.clone().cast_to(Type::ssize_t());
1076+
let cast_src_ptr = src_ptr.clone().cast_to(Type::ssize_t());
1077+
let offset_overflow = cast_dst_ptr.sub_overflow(cast_src_ptr);
1078+
1079+
// Re-compute the offset with standard substraction (no casts this time)
1080+
let ptr_offset_expr = dst_ptr.sub(src_ptr);
1081+
(ptr_offset_expr, offset_overflow)
1082+
}
1083+
10391084
/// A transmute is a bitcast from the argument type to the return type.
10401085
/// https://doc.rust-lang.org/std/intrinsics/fn.transmute.html
10411086
///

kani-compiler/src/main.rs

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
//! Like miri, clippy, and other tools developed on the top of rustc, we rely on the
88
//! rustc_private feature and a specific version of rustc.
99
#![deny(warnings)]
10-
#![feature(bool_to_option)]
1110
#![feature(crate_visibility_modifier)]
1211
#![feature(extern_types)]
1312
#![feature(nll)]

rust-toolchain.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
# SPDX-License-Identifier: Apache-2.0 OR MIT
33

44
[toolchain]
5-
channel = "nightly-2022-05-03"
5+
channel = "nightly-2022-05-17"
66
components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
//! Check that Kani correctly detects a safety violation when user tries to invoke the
4+
//! `ptr_offset_from_unsigned` intrinsic in the wrong order.
5+
6+
#![feature(core_intrinsics)]
7+
use std::intrinsics::ptr_offset_from_unsigned;
8+
9+
#[kani::proof]
10+
fn check_failure() {
11+
let a = [0; 5];
12+
let ptr0: *const i32 = &a[0];
13+
let ptr1: *const i32 = &a[1];
14+
unsafe {
15+
let _distance = ptr_offset_from_unsigned(ptr0, ptr1);
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Failed Checks: attempt to compute unsigned offset with negative distance
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
//! Checks that the ptr_offset_from_unsigned intrinsic returns the expected results.
4+
5+
#![feature(core_intrinsics)]
6+
use std::intrinsics::ptr_offset_from_unsigned;
7+
8+
#[kani::proof]
9+
fn check_distance_i32() {
10+
let a = [0; 5];
11+
let ptr0: *const i32 = &a[0];
12+
let ptr1: *const i32 = &a[1];
13+
let ptr2: *const i32 = &a[2];
14+
unsafe {
15+
assert_eq!(ptr_offset_from_unsigned(ptr2, ptr0), 2);
16+
assert_eq!(ptr_offset_from_unsigned(ptr1, ptr0), 1);
17+
assert_eq!(ptr_offset_from_unsigned(ptr2, ptr2), 0);
18+
}
19+
}
20+
21+
#[kani::proof]
22+
fn check_distance_i64() {
23+
let a = [0i64; 5];
24+
let ptr0: *const i64 = &a[0];
25+
let ptr1: *const i64 = &a[1];
26+
let ptr2: *const i64 = &a[2];
27+
unsafe {
28+
assert_eq!(ptr_offset_from_unsigned(ptr2, ptr0), 2);
29+
assert_eq!(ptr_offset_from_unsigned(ptr1, ptr0), 1);
30+
assert_eq!(ptr_offset_from_unsigned(ptr1, ptr1), 0);
31+
}
32+
}

tools/bookrunner/librustdoc/clean/inline.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::clean::{
2626
use crate::core::DocContext;
2727
use crate::formats::item_type::ItemType;
2828

29-
type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
29+
type Attrs<'hir> = &'hir [ast::Attribute];
3030

3131
/// Attempt to inline a definition into this AST.
3232
///
@@ -159,7 +159,7 @@ crate fn try_inline_glob(
159159
}
160160

161161
fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> {
162-
cx.tcx.get_attrs(did)
162+
cx.tcx.get_attrs_unchecked(did)
163163
}
164164

165165
/// Record an external fully qualified name in the external_paths cache.
@@ -685,7 +685,7 @@ crate fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
685685

686686
let trait_ = clean::TraitWithExtraInfo {
687687
trait_,
688-
is_notable: clean::utils::has_doc_flag(cx.tcx.get_attrs(did), sym::notable_trait),
688+
is_notable: clean::utils::has_doc_flag(cx.tcx, did, sym::notable_trait),
689689
};
690690
cx.external_traits.borrow_mut().insert(did, trait_);
691691
cx.active_extern_traits.remove(&did);

tools/bookrunner/librustdoc/clean/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
1919
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
2020
use rustc_middle::middle::resolve_lifetime as rl;
2121
use rustc_middle::ty::subst::{InternalSubsts, Subst};
22-
use rustc_middle::ty::{self, AdtKind, DefIdTree, Lift, Ty, TyCtxt};
22+
use rustc_middle::ty::{self, AdtKind, DefIdTree, EarlyBinder, Lift, Ty, TyCtxt};
2323
use rustc_middle::{bug, span_bug};
2424
use rustc_span::hygiene::{AstPass, MacroKind};
2525
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -1544,7 +1544,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
15441544
.tcx
15451545
.explicit_item_bounds(def_id)
15461546
.iter()
1547-
.map(|(bound, _)| bound.subst(cx.tcx, substs))
1547+
.map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
15481548
.collect::<Vec<_>>();
15491549
let mut regions = vec![];
15501550
let mut has_sized = false;

tools/bookrunner/librustdoc/clean/types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ impl Item {
197197
kind: ItemKind,
198198
cx: &mut DocContext<'_>,
199199
) -> Item {
200-
let ast_attrs = cx.tcx.get_attrs(def_id);
200+
let ast_attrs = cx.tcx.get_attrs_unchecked(def_id);
201201

202202
Self::from_def_id_and_attrs_and_parts(def_id, name, kind, box ast_attrs.clean(cx), cx)
203203
}

tools/bookrunner/librustdoc/clean/utils.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -287,10 +287,9 @@ where
287287
///
288288
/// This function exists because it runs on `hir::Attributes` whereas the other is a
289289
/// `clean::Attributes` method.
290-
crate fn has_doc_flag(attrs: ty::Attributes<'_>, flag: Symbol) -> bool {
291-
attrs.iter().any(|attr| {
292-
attr.has_name(sym::doc)
293-
&& attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
290+
crate fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool {
291+
tcx.get_attrs(did, sym::doc).any(|attr| {
292+
attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
294293
})
295294
}
296295

0 commit comments

Comments
 (0)