Skip to content

Commit

Permalink
first tests of the creusot/tests directory, executed successfully
Browse files Browse the repository at this point in the history
  • Loading branch information
SCHNEIDER Laurent committed Jan 16, 2025
1 parent d90784e commit fce44ed
Show file tree
Hide file tree
Showing 312 changed files with 4,449 additions and 4,321 deletions.
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions creusot-contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ description = "Provides contracts and logic helpers for Creusot"
creusot-contracts-proc = { path = "../creusot-contracts-proc", version = "0.3.0" }
creusot-contracts-dummy = { path = "../creusot-contracts-dummy", version = "0.3.0" }
num-rational = "0.3.2"
paste = "1.0"

[features]
default = []
Expand Down
43 changes: 23 additions & 20 deletions creusot-contracts/src/std/num.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{Default, *};
pub use ::std::num::*;
use paste::paste;

macro_rules! mach_int {
($t:ty, $ty_nm:expr, $zero:expr) => {
Expand Down Expand Up @@ -34,30 +35,32 @@ macro_rules! mach_int {

macro_rules! mach_uint { // TODO laurent factoriser avec mach_int
($t:ty, $ty_nm:expr, $zero:expr) => {
impl View for $t {
type ViewTy = Int;
#[logic]
#[trusted]
#[creusot::builtins = concat!($ty_nm, ".to_uint")]
fn view(self) -> Self::ViewTy {
dead
paste! {
impl View for $t {
type ViewTy = Int;
#[logic]
#[trusted]
#[creusot::builtins = $ty_nm ".t'int"] // TODO laurent: on ne génère pas ".to_int" pour les types non signé car on a besoin de la version non signée, or le clone substitue la
fn view(self) -> Self::ViewTy {
dead
}
}
}

impl DeepModel for $t {
type DeepModelTy = Int;
#[logic]
#[open]
fn deep_model(self) -> Self::DeepModelTy {
pearlite! { self@ }
impl DeepModel for $t {
type DeepModelTy = Int;
#[logic]
#[open]
fn deep_model(self) -> Self::DeepModelTy {
pearlite! { self@ }
}
}
}

impl Default for $t {
#[predicate]
#[open]
fn is_default(self) -> bool {
pearlite! { self == $zero }
impl Default for $t {
#[predicate]
#[open]
fn is_default(self) -> bool {
pearlite! { self == $zero }
}
}
}
};
Expand Down
4 changes: 4 additions & 0 deletions creusot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ serde_json = { version = "1.0" }
lazy_static = "1.4.0"
pathdiff = "0.2"

[build-dependencies]
paste = "1.0"
indoc = "2.0.5"

[dev-dependencies]
regex = "1.10.5"
glob = "*"
Expand Down
204 changes: 204 additions & 0 deletions creusot/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
use std::{env, error::Error, fs::{self, File}, io::{self, Write}, path::{Path, PathBuf}};
use indoc::indoc;

fn int_prelude_maker(filepath: &impl AsRef<Path>) -> Result<(), Box<dyn Error>> {
// generate coma code for unsigned integer
macro_rules! uint_mod {
($writer: ident, $n: literal) => {
::paste::paste! {
let m = format!(indoc! {r#"
module {module_name}
use export bv.{BV_name}
use bv.BV256 as BV256
use bv.{BVConverter_name}
use int.Int
use int.EuclideanDivision as ED
constant max_uint : t = 0x{max_value:X}
function to_BV256 (x: t) : BV256.t = toBig x
function of_BV256 (x: BV256.t) : t = toSmall x
function bv256_to_int (x: BV256.t) : int = BV256.t'int x
constant max_uint_as_BV256 : BV256.t = to_BV256 max_uint
let eq (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a = to_int b }} {{ result <-> a = b }}) = any
let ne (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a <> to_int b }} {{ result <-> a <> b }}) = any
let le (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a <= to_int b }} {{ result <-> ule a b }}) = any
let lt (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a < to_int b }} {{ result <-> ult a b }}) = any
let ge (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a >= to_int b }} {{ result <-> uge a b }}) = any
let gt (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a > to_int b }} {{ result <-> ugt a b }}) = any
let add (a:t) (b:t)
{{ [@expl:arithmetic overflow] to_int a + to_int b < two_power_size \/ BV256.ule (BV256.add (to_BV256 a) (to_BV256 b)) max_uint_as_BV256 }}
(ret (result :t) {{ to_int result = to_int a + to_int b }} {{ result = add a b }})
= any
let sub (a:t) (b:t)
{{ [@expl:arithmetic overflow] to_int a >= to_int b \/ uge a b }}
(ret (result: t) {{ to_int result = to_int a - to_int b }} {{ result = sub a b }})
= any
let mul (a:t) (b:t)
{{ [@expl:arithmetic overflow] to_int a * to_int b < two_power_size \/ BV256.ule (BV256.mul (to_BV256 a) (to_BV256 b)) max_uint_as_BV256 }}
(ret (result: t) {{ result = mul a b }} {{ to_int result = to_int a * to_int b }})
= any
let div (a:t) (b:t)
{{ [@expl:division by zero] b <> zeros \/ to_int b <> 0 }}
(ret (result: t) {{ to_int result = ED.div (to_int a) (to_int b) }} {{ result = udiv a b }})
= any
let rem (a:t) (b:t)
{{ [@expl:remainder by zero] b <> zeros \/ to_int b <> 0 }}
(ret (result: t) {{ to_int result = ED.mod (to_int a) (to_int b) }} {{ result = urem a b }})
= any
let bw_and (a:t) (b:t) (ret (result :t)) = ret {{ bw_and a b }}
let bw_or (a:t) (b:t) (ret (result :t)) = ret {{ bw_or a b }}
let bw_xor (a:t) (b:t) (ret (result :t)) = ret {{ bw_xor a b }}
let bw_not (a:t) (ret (result :t)) = ret {{ bw_not a }}
let shl (a:t) (b:int)
{{ [@expl:out-of-bounds shifting] b >= 0 /\ b <= size }}
(ret (result :t) {{ result = lsl_bv a (of_int b) }} {{ result = lsl a b }})
= any
let shr (a:t) (b:int)
{{ [@expl:out-of-bounds shifting] b >= 0 /\ b <= size }}
(ret (result :t) {{ result = lsr_bv a (of_int b) }} {{ result = lsr a b }})
= any
let to_bv256 (a:t)
(ret (result: BV256.t) {{ result = to_BV256 a }})
= any
let of_bv256 (a:BV256.t)
{{ [@expl:arithmetic overflow] bv256_to_int a >= 0 /\ bv256_to_int a < two_power_size }}
(ret (result: t) {{ result = of_BV256 a }})
= any
end
"#}, module_name = stringify!([<UInt $n>]), BV_name = stringify!([<BV $n>]), BVConverter_name = stringify!([<BVConverter_ $n _256>]), max_value = [<u $n>]::MAX);

$writer.write_all(m.as_bytes())?;
}
};
}

// generate coma code for signed integer
macro_rules! int_mod {
($writer: ident, $n: literal) => {
::paste::paste! {
let m = format!(indoc! {r#"
module {module_name}
use export bv.{BV_name}
use bv.BV256 as BV256
use bv.{BVConverter_name}
use bv.Pow2int
use int.Int
use int.ComputerDivision as CD
constant min_sint : t = 0x{min_value:X}
constant max_sint : t = 0x{max_value:X}
constant minus_one : t = 0x{max_uint_value:X}
function to_BV256 (x: t) : BV256.t = stoBig x
function of_BV256 (x: BV256.t) : t = toSmall x
function bv256_to_int (x: BV256.t) : int = BV256.t'int x
constant min_sint_as_BV256 : BV256.t = to_BV256 min_sint
constant max_sint_as_BV256 : BV256.t = to_BV256 max_sint
let eq (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a = to_int b }} {{ result <-> a = b }}) = any
let ne (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a <> to_int b }} {{ result <-> a <> b }}) = any
let le (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a <= to_int b }} {{ result <-> sle a b }}) = any
let lt (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a < to_int b }} {{ result <-> slt a b }}) = any
let ge (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a >= to_int b }} {{ result <-> sge a b }}) = any
let gt (a: t) (b: t) (ret (result: bool) {{ result <-> to_int a > to_int b }} {{ result <-> sgt a b }}) = any
let add (a:t) (b:t)
{{ [@expl:arithmetic overflow] - two_power_size_minus_one <= to_int a + to_int b < two_power_size_minus_one \/ let r = BV256.add (to_BV256 a) (to_BV256 b) in (BV256.sle min_sint_as_BV256 r /\ BV256.sle r max_sint_as_BV256) }}
(ret (result :t) {{ to_int result = to_int a + to_int b }} {{ result = add a b }})
= any
let sub (a:t) (b:t)
{{ [@expl:arithmetic overflow] - two_power_size_minus_one <= to_int a - to_int b < two_power_size_minus_one \/ let r = BV256.sub (to_BV256 a) (to_BV256 b) in (BV256.sle min_sint_as_BV256 r /\ BV256.sle r max_sint_as_BV256) }}
(ret (result: t) {{ to_int result = to_int a - to_int b }} {{ result = sub a b }})
= any
let mul (a:t) (b:t)
{{ [@expl:arithmetic overflow] - two_power_size_minus_one <= to_int a * to_int b < two_power_size_minus_one \/ let r = BV256.mul (to_BV256 a) (to_BV256 b) in (BV256.sle min_sint_as_BV256 r /\ BV256.sle r max_sint_as_BV256) }}
(ret (result: t) {{ to_int result = to_int a * to_int b }} {{ result = mul a b }})
= any
let div (a:t) (b:t)
{{ [@expl:division by zero] b <> zeros \/ to_int b <> 0 }}
{{ [@expl:signed division overflow check] (a <> min_sint \/ b <> minus_one) \/ (to_int a <> to_int min_sint \/ to_int b <> -1) }}
(ret (result: t) {{ to_int result = CD.div (to_int a) (to_int b) }} {{ result = sdiv a b }})
= any
let rem (a:t) (b:t)
{{ [@expl:remainder by zero] b <> zeros \/ to_int b <> 0 }}
(ret (result: t) {{ to_int result = CD.mod (to_int a) (to_int b) }} {{ result = srem a b }})
= any
let bw_and (a:t) (b:t) (ret (result :t)) = ret {{ bw_and a b }}
let bw_or (a:t) (b:t) (ret (result :t)) = ret {{ bw_or a b }}
let bw_xor (a:t) (b:t) (ret (result :t)) = ret {{ bw_xor a b }}
let bw_not (a:t) (ret (result :t)) = ret {{ bw_not a }}
let shl (a:t) (b:int)
{{ [@expl:out-of-bounds shifting] ult (of_int b) size_bv \/ b < size }}
{{ [@expl:out-of-bounds shifting] sle zeros a \/ to_int a >= 0 }}
{{ [@expl:arithmetic overflow] (to_int a) * (pow2 (b)) < two_power_size_minus_one \/ let r = BV256.lsl_bv (to_BV256 a) (to_BV256 (of_int b)) in (BV256.sle min_sint_as_BV256 r /\ BV256.sle r max_sint_as_BV256)}}
(ret (result :t) {{ result = lsl_bv a (of_int b) }} {{ result = lsl a b }})
= any
let shr (a:t) (b:int)
{{ [@expl:out-of-bounds shifting] ult (of_int b) size_bv \/ b < size }}
(ret (result :t) {{ result = asr_bv a (of_int b) }} {{ result = asr a b }})
= any
let to_bv256 (a:t)
(ret (result: BV256.t) {{ result = to_BV256 a }})
= any
let of_bv256 (a:BV256.t)
{{ [@expl:arithmetic overflow] bv256_to_int a >= 0 /\ bv256_to_int a < two_power_size }}
(ret (result: t) {{ result = of_BV256 a }})
= any
end
"#}, module_name = stringify!([<Int $n>]), BV_name = stringify!([<BV $n>]), BVConverter_name = stringify!([<BVConverter_ $n _256>]), min_value = [<i $n>]::MIN, max_value = [<i $n>]::MAX, max_uint_value= [<u $n>]::MAX);

$writer.write_all(m.as_bytes())?;
}
};
}

// create or open the file
let file = File::create(filepath.as_ref())?;
let mut writer = io::BufWriter::new(file);

// unsigned integer
uint_mod!(writer, 8);
uint_mod!(writer, 16);
uint_mod!(writer, 32);
uint_mod!(writer, 64);
uint_mod!(writer, 128);

// signed integer
int_mod!(writer, 8);
int_mod!(writer, 16);
int_mod!(writer, 32);
int_mod!(writer, 64);
int_mod!(writer, 128);

writer.flush()?;
Ok(())
}

fn main() {
// rerun this build script if it has changed
println!("cargo:rerun-if-changed=build.rs");

// Get the path to the crate directory
let crate_dirpath = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR doesn't exist for creusot crate ??"));

// Get the path to the prelude directory
let prelude_dirpath = crate_dirpath.join("..").join("prelude");

// We create the directory if it does not exist
fs::create_dir_all(&prelude_dirpath).expect("creusot crate build, can't create prelude directory");

// Create the file name for the prelude dedicated to integers
let int_prelude_filepath = prelude_dirpath.join("int.coma");

// create integer prelude
int_prelude_maker(&int_prelude_filepath).unwrap_or_else(|e| {
eprintln!("Erreur in int_prelude_maker: {}", e);
std::process::exit(1);
});
}
31 changes: 26 additions & 5 deletions creusot/src/backend/program.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use self::ty::{concret_intty, concret_uintty, slice_create_qname, slice_length_qname};
use self::ty::{concret_intty, concret_uintty, intty_to_ty, slice_create_qname, slice_length_qname, uintty_to_ty};

use crate::{
backend::{
Expand Down Expand Up @@ -353,7 +353,7 @@ impl<'tcx> RValue<'tcx> {
// todo laurent valider l'approche
match r_ty.kind() {
TyKind::Int(_) => module.push_ident("to_int"),
TyKind::Uint(_) => module.push_ident("to_uint"),
TyKind::Uint(_) => module.push_ident(".t'int"),
_ => unreachable!("right operande, non-integer type for binary operation {op:?} {ty:?}"),
}

Expand Down Expand Up @@ -619,8 +619,10 @@ impl<'tcx> Terminator<'tcx> {
match self {
Terminator::Goto(bb) => (istmts, Expr::Symbol(format!("bb{}", bb.as_usize()).into())),
Terminator::Switch(switch, branches) => {
let ty = switch.ty(lower.ctx.tcx, lower.locals);
let ty_kind = ty.kind();
let discr = switch.to_why(lower, &mut istmts);
(istmts, branches.to_why(lower.ctx, lower.names, discr))
(istmts, branches.to_why(lower.ctx, lower.names, discr, ty_kind))
}
Terminator::Return => {
(istmts, Expr::Symbol("return".into()).app(vec![Arg::Term(Exp::var("_0"))]))
Expand All @@ -642,21 +644,40 @@ impl<'tcx> Branches<'tcx> {
ctx: &mut Why3Generator<'tcx>,
names: &mut N,
discr: Exp,
discr_ty: &'tcx TyKind<'tcx>,
) -> coma::Expr {
match self {
Branches::Int(brs, def) => {
let intty = match discr_ty {
TyKind::Int(intty) => intty,
_ => panic!("Branches::Int try to evaluate a type that is not Int"),
};

let mut brs = mk_switch_branches(
discr,
brs.into_iter().map(|(val, tgt)| (Exp::int(val), mk_goto(tgt))).collect(),
brs.into_iter().map(|(val, tgt)| {
let why_ty = intty_to_ty(names, intty);
let e = Exp::Const(Constant::Int(val, Some(why_ty)));
(e, mk_goto(tgt))
}).collect(),
);

brs.push(Defn::simple("default", Expr::BlackBox(Box::new(mk_goto(def)))));
Expr::Defn(Box::new(Expr::Any), false, brs)
}
Branches::Uint(brs, def) => {
let uintty = match discr_ty {
TyKind::Uint(uintty) => uintty,
_ => panic!("Branches::Uint try to evaluate a type that is not Uint"),
};

let mut brs = mk_switch_branches(
discr,
brs.into_iter().map(|(val, tgt)| (Exp::uint(val), mk_goto(tgt))).collect(),
brs.into_iter().map(|(val, tgt)| {
let why_ty = uintty_to_ty(names, uintty);
let e = Exp::Const(Constant::Uint(val, Some(why_ty)));
(e, mk_goto(tgt))
}).collect(),
);

brs.push(Defn::simple("default", Expr::BlackBox(Box::new(mk_goto(def)))));
Expand Down
Loading

0 comments on commit fce44ed

Please sign in to comment.