Skip to content

Commit dad0353

Browse files
committed
Fix encoding of signed integer divisions
1 parent 519ff34 commit dad0353

File tree

6 files changed

+59
-9
lines changed

6 files changed

+59
-9
lines changed

docs/dev-guide/src/config/flags.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
| [`SERVER_ADDRESS`](#server_address) | `Option<String>` | `None` | A |
6161
| [`SERVER_MAX_CONCURRENCY`](#server_max_concurrency) | `Option<usize>` | `None` | A |
6262
| [`SERVER_MAX_STORED_VERIFIERS`](#server_max_stored_verifiers) | `Option<usize>` | `None` | A |
63-
| [`SIMPLIFY_ENCODING`](#simplify_encoding) | `bool` | `true` | A |
63+
| [`SIMPLIFY_ENCODING`](#simplify_encoding) | `bool` | `false` | A |
6464
| [`SKIP_UNSUPPORTED_FEATURES`](#skip_unsupported_features) | `bool` | `false` | A |
6565
| [`SMT_QI_BOUND_GLOBAL`](#smt_qi_bound_global) | `Option<u64>` | `None` | A |
6666
[`SMT_QI_BOUND_GLOBAL_KIND`](#smt_qi_bound_global_kind) | `Option<u64>` | `None` | A |

prusti-tests/tests/verify_overflow/fail/issues/issue-1505.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use prusti_contracts::*;
22

33
// To inhibit constant-propagation optimizations:
44
#[pure]
5-
fn id<T>(x: T) -> T { x}
5+
fn id<T: Copy>(x: T) -> T { x }
66

77
fn check_division(){
88
assert!(id(3i32) / 2 == 1);
@@ -23,6 +23,10 @@ fn check_modulo() {
2323
assert!(id(10) % -3 == 1);
2424
assert!(id(-10) % 3 == -1);
2525
assert!(id(-10) % -3 == -1);
26+
prusti_assert!(id(10) % 3 == 1);
27+
prusti_assert!(id(10) % -3 == 1);
28+
prusti_assert!(id(-10) % 3 == -1);
29+
prusti_assert!(id(-10) % -3 == -1);
2630

2731
assert!(id(3) % 3 == 0);
2832
assert!(id(2) % 3 == 2);
@@ -33,8 +37,18 @@ fn check_modulo() {
3337
assert!(id(-3) % 3 == 0);
3438
assert!(id(-4) % 3 == -1);
3539
assert!(id(-5) % 3 == -2);
40+
prusti_assert!(id(3) % 3 == 0);
41+
prusti_assert!(id(2) % 3 == 2);
42+
prusti_assert!(id(1) % 3 == 1);
43+
prusti_assert!(id(0) % 3 == 0);
44+
prusti_assert!(id(-1) % 3 == -1);
45+
prusti_assert!(id(-2) % 3 == -2);
46+
prusti_assert!(id(-3) % 3 == 0);
47+
prusti_assert!(id(-4) % 3 == -1);
48+
prusti_assert!(id(-5) % 3 == -2);
3649

3750
assert!(id(-4) % 2 == 0);
51+
prusti_assert!(id(-4) % 2 == 0);
3852

3953
// Smoke test
4054
assert!(false); //~ ERROR the asserted expression might not hold

prusti-utils/src/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ lazy_static::lazy_static! {
8282
settings.set_default("check_panics", true).unwrap();
8383
settings.set_default("encode_unsigned_num_constraint", true).unwrap();
8484
settings.set_default("encode_bitvectors", false).unwrap();
85-
settings.set_default("simplify_encoding", true).unwrap();
85+
settings.set_default("simplify_encoding", false).unwrap();
8686
settings.set_default("log", "").unwrap();
8787
settings.set_default("log_style", "auto").unwrap();
8888
settings.set_default("log_dir", "log").unwrap();

prusti-viper/src/encoder/mir_encoder/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,13 @@ impl<'p, 'v: 'p, 'tcx: 'v> MirEncoder<'p, 'v, 'tcx> {
494494
vir::Expr::rem(left, right)
495495
}
496496
}
497-
mir::BinOp::Div => vir::Expr::div(left, right),
497+
mir::BinOp::Div => {
498+
if matches!(ty.kind(), ty::TyKind::Uint(_)) {
499+
vir::Expr::unsigned_div(left, right)
500+
} else {
501+
vir::Expr::div(left, right)
502+
}
503+
}
498504
mir::BinOp::MulUnchecked | mir::BinOp::Mul => vir::Expr::mul(left, right),
499505
mir::BinOp::BitAnd if is_bool => vir::Expr::and(left, right),
500506
mir::BinOp::BitOr if is_bool => vir::Expr::or(left, right),

vir/defs/polymorphic/ast/expr.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ __binary_op__! {
151151
add Add,
152152
sub Sub,
153153
mul Mul,
154-
div Div,
154+
unsigned_div Div,
155155
modulo Mod,
156156
and And,
157157
or Or,
@@ -315,8 +315,21 @@ impl Expr {
315315
Expr::not(Expr::eq_cmp(left, right))
316316
}
317317

318-
#[allow(clippy::should_implement_trait)]
319-
/// Encode Rust reminder. This is *not* Viper modulo.
318+
/// Encode Rust's division. This is *not* Viper's division.
319+
pub fn div(left: Expr, right: Expr) -> Self {
320+
Expr::ite(
321+
Expr::or(
322+
Expr::ge_cmp(left.clone(), 0.into()),
323+
Expr::eq_cmp(Expr::modulo(left.clone(), right.clone()), 0.into()),
324+
),
325+
// positive value or left % right == 0
326+
Expr::unsigned_div(left.clone(), right.clone()),
327+
// negative value
328+
Expr::minus(Expr::unsigned_div(Expr::minus(left), right)),
329+
)
330+
}
331+
332+
/// Encode Rust's signed reminder. This is *not* Viper's modulo.
320333
pub fn rem(left: Expr, right: Expr) -> Self {
321334
let abs_right = Expr::ite(
322335
Expr::ge_cmp(right.clone(), 0.into()),

vir/src/legacy/ast/expr.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,8 @@ impl Expr {
561561
}
562562

563563
#[allow(clippy::should_implement_trait)]
564-
pub fn div(left: Expr, right: Expr) -> Self {
564+
/// Encode Rust's unsigned division. This is the same as Viper's division.
565+
pub fn unsigned_div(left: Expr, right: Expr) -> Self {
565566
Expr::BinOp(
566567
BinaryOpKind::Div,
567568
Box::new(left),
@@ -570,6 +571,22 @@ impl Expr {
570571
)
571572
}
572573

574+
#[allow(clippy::should_implement_trait)]
575+
/// Encode Rust's division. This is *not* Viper's division.
576+
pub fn div(left: Expr, right: Expr) -> Self {
577+
Expr::ite(
578+
Expr::or(
579+
Expr::ge_cmp(left.clone(), 0.into()),
580+
Expr::eq_cmp(Expr::modulo(left.clone(), right.clone()), 0.into()),
581+
),
582+
// positive value or left % right == 0
583+
Expr::unsigned_div(left.clone(), right.clone()),
584+
// negative value
585+
Expr::minus(Expr::unsigned_div(Expr::minus(left), right)),
586+
)
587+
}
588+
589+
/// Encode Rust's unsigned reminder. This is the same as Viper's modulo.
573590
pub fn modulo(left: Expr, right: Expr) -> Self {
574591
Expr::BinOp(
575592
BinaryOpKind::Mod,
@@ -580,7 +597,7 @@ impl Expr {
580597
}
581598

582599
#[allow(clippy::should_implement_trait)]
583-
/// Encode Rust reminder. This is *not* Viper modulo.
600+
/// Encode Rust's signed reminder. This is *not* Viper's modulo.
584601
pub fn rem(left: Expr, right: Expr) -> Self {
585602
let abs_right = Expr::ite(
586603
Expr::ge_cmp(right.clone(), 0.into()),

0 commit comments

Comments
 (0)