From 9b82a9e2752efef56bdf1a9ddfa664c7401855ba Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Fri, 31 Jul 2020 18:20:57 -0600 Subject: [PATCH 001/109] Added a Cargo build example --- examples/rust-cargo/.cargo/config.toml | 2 + examples/rust-cargo/.gitignore | 3 + examples/rust-cargo/Cargo.toml | 14 + examples/rust-cargo/src/main.rs | 11 + smack/.gitignore | 3 + smack/Cargo.toml | 17 + smack/build.rs | 12 + smack/src/lib.rs | 551 +++++++++++++++++++++++++ smack/src/smack.c | 539 ++++++++++++++++++++++++ smack/src/smack.h | 178 ++++++++ 10 files changed, 1330 insertions(+) create mode 100644 examples/rust-cargo/.cargo/config.toml create mode 100644 examples/rust-cargo/.gitignore create mode 100644 examples/rust-cargo/Cargo.toml create mode 100644 examples/rust-cargo/src/main.rs create mode 100644 smack/.gitignore create mode 100644 smack/Cargo.toml create mode 100644 smack/build.rs create mode 100644 smack/src/lib.rs create mode 100644 smack/src/smack.c create mode 100644 smack/src/smack.h diff --git a/examples/rust-cargo/.cargo/config.toml b/examples/rust-cargo/.cargo/config.toml new file mode 100644 index 000000000..b42fc7700 --- /dev/null +++ b/examples/rust-cargo/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-A", "unused-imports", "-C", "opt-level=0", "-g", "--cfg", "verifier=\"smack\"", "--emit=llvm-ir"] diff --git a/examples/rust-cargo/.gitignore b/examples/rust-cargo/.gitignore new file mode 100644 index 000000000..693699042 --- /dev/null +++ b/examples/rust-cargo/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +Cargo.lock diff --git a/examples/rust-cargo/Cargo.toml b/examples/rust-cargo/Cargo.toml new file mode 100644 index 000000000..ffb44d503 --- /dev/null +++ b/examples/rust-cargo/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rust-cargo" +version = "0.1.0" +authors = ["Shaobo He "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +smack = { path = "../../smack"} + +[profile.dev] +incremental=false + diff --git a/examples/rust-cargo/src/main.rs b/examples/rust-cargo/src/main.rs new file mode 100644 index 000000000..9a1f74226 --- /dev/null +++ b/examples/rust-cargo/src/main.rs @@ -0,0 +1,11 @@ +#[macro_use] +extern crate smack; +use smack::*; + +// @expect error + +fn main() { + let a = 2; + let b = 3; + smack::assert!(a + b != 5); +} diff --git a/smack/.gitignore b/smack/.gitignore new file mode 100644 index 000000000..693699042 --- /dev/null +++ b/smack/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +Cargo.lock diff --git a/smack/Cargo.toml b/smack/Cargo.toml new file mode 100644 index 000000000..7e6757f16 --- /dev/null +++ b/smack/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "smack" +version = "0.1.0" +authors = ["Shaobo He "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +[lib] +crate-type = ['rlib'] + +[build-dependencies] +cc = "1.0" + +[profile.dev] +incremental=false diff --git a/smack/build.rs b/smack/build.rs new file mode 100644 index 000000000..855d4c3f3 --- /dev/null +++ b/smack/build.rs @@ -0,0 +1,12 @@ +// build.rs + +fn main() { + cc::Build::new() + .file("src/smack.c") + .define("RUST_EXEC", None) + .include("src") + .compiler("clang") + .compile("libsmack.a"); + println!("cargo:rerun-if-changed=src/smack.c"); +} + diff --git a/smack/src/lib.rs b/smack/src/lib.rs new file mode 100644 index 000000000..21ec33bc3 --- /dev/null +++ b/smack/src/lib.rs @@ -0,0 +1,551 @@ +#![crate_type = "staticlib"] + +#[cfg(verifier = "smack")] +extern "C" { + pub fn __VERIFIER_assert(x: i32); + pub fn __VERIFIER_assume(x: i32); + pub fn __VERIFIER_nondet_signed_char() -> i8; + pub fn __VERIFIER_nondet_unsigned_char() -> u8; + pub fn __VERIFIER_nondet_signed_short() -> i16; + pub fn __VERIFIER_nondet_unsigned_short() -> u16; + pub fn __VERIFIER_nondet_signed_int() -> i32; + pub fn __VERIFIER_nondet_unsigned_int() -> u32; + pub fn __VERIFIER_nondet_signed_long_long() -> i64; + pub fn __VERIFIER_nondet_unsigned_long_long() -> u64; + pub fn malloc(size: usize) -> *mut u8; + pub fn __VERIFIER_memcpy(dest: *mut u8, src: *mut u8, count: usize) -> *mut u8; + pub fn free(ptr: *mut u8); +} + +#[macro_export] +macro_rules! verifier_assert { + ( $cond:expr ) => { + unsafe { + __VERIFIER_assert($cond as i32); + }; + }; +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! print { + ($fmt:expr) => (); + ($fmt:expr, $($arg:expr),*) => ( $($arg);* ) +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! println { + ($($arg:tt)*) => ( print!($($arg)*) ) +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! eprint { + ($($arg:tt)*) => ( print!($($arg)*) ) +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! eprintln { + ($($arg:tt)*) => ( print!($($arg)*) ) +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! assert { + ( $cond:expr ) => { + verifier_assert!($cond); + }; +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! assert_eq { + ( $lhs:expr, $rhs:expr ) => { + smack::assert!($lhs == $rhs); + }; +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! assert_neq { + ( $lhs:expr, $rhs:expr ) => { + smack::assert!($lhs != $rhs); + }; +} + +#[macro_export] +macro_rules! verifier_assume { + ( $cond:expr ) => { + #[cfg(verifier = "smack")] + unsafe { + __VERIFIER_assume($cond as i32); + } + + #[cfg(not(verifier = "smack"))] + (); + }; +} + +#[macro_export] +macro_rules! assume { + ( $cond:expr ) => { + verifier_assume!($cond); + }; +} + +#[macro_export] +macro_rules! verifier_nondet { + ($e:expr) => + ( + #[cfg(verifier = "smack")] + $e.verifier_nondet() + + #[cfg(not(verifier = "smack"))] + $e + ) +} + +pub trait VerifierNonDet { + fn verifier_nondet(self) -> Self; +} + +#[macro_export] +macro_rules! make_verifier_nondet { + ($typ:ident, $nondet:ident) => { + impl VerifierNonDet for $typ { + #[cfg(verifier = "smack")] + fn verifier_nondet(self) -> Self { + unsafe { $nondet() as Self } + } + + #[cfg(not(verifier = "smack"))] + fn verifier_nondet(self) -> Self { + self + } + } + }; +} + +/* Instantiate nondet for all integer types. */ +make_verifier_nondet!(i8, __VERIFIER_nondet_signed_char); +make_verifier_nondet!(u8, __VERIFIER_nondet_unsigned_char); +make_verifier_nondet!(i16, __VERIFIER_nondet_signed_short); +make_verifier_nondet!(u16, __VERIFIER_nondet_unsigned_short); +make_verifier_nondet!(i32, __VERIFIER_nondet_signed_int); +make_verifier_nondet!(u32, __VERIFIER_nondet_unsigned_int); +make_verifier_nondet!(i64, __VERIFIER_nondet_signed_long_long); +make_verifier_nondet!(u64, __VERIFIER_nondet_unsigned_long_long); +make_verifier_nondet!(isize, __VERIFIER_nondet_signed_long_long); +make_verifier_nondet!(usize, __VERIFIER_nondet_unsigned_long_long); + +#[cfg(not(verifier = "smack"))] +#[cfg(feature = "std")] +#[allow(dead_code)] +use std::Vec; +/* Vector class. +Based on https://doc.rust-lang.org/nomicon/vec-final.html */ +#[cfg(verifier = "smack")] +#[allow(dead_code)] +fn sized_realloc(orig_ptr: *mut u8, orig_size: usize, new_size: usize) -> *mut u8 { + unsafe { + let result: *mut u8 = malloc(new_size); + __VERIFIER_memcpy(result, orig_ptr, orig_size); + result + } +} + +#[cfg(verifier = "smack")] +use std::mem; +#[cfg(verifier = "smack")] +use std::ops::{Deref, DerefMut}; +#[cfg(verifier = "smack")] +use std::ptr::{self, null}; + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +pub struct PhantomData { + _place_holder: *const T, + _padding: u64, +} + +#[cfg(verifier = "smack")] +impl Default for PhantomData { + fn default() -> Self { + PhantomData:: { + _place_holder: ptr::null(), + _padding: 0, + } + } +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +struct Unique { + // _marker: PhantomData, // For the drop checker + ptr: *const T, // *const for variance + _marker: u64, +} + +#[cfg(verifier = "smack")] +impl Unique { + pub fn new(ptr: *mut T) -> Self { + Unique { + ptr: ptr, + _marker: Default::default(), + } + } + + pub fn as_ptr(&self) -> *mut T { + self.ptr as *mut T + } +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +struct RawVec { + ptr: Unique, + cap: usize, +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +impl RawVec { + fn new() -> Self { + let elem_size = mem::size_of::(); + let cap = 32; + let ptr = unsafe { Unique::new(malloc(cap * elem_size) as *mut T) }; + RawVec { ptr: ptr, cap: cap } + } + + fn new_with_capacity(cap: usize) -> Self { + let elem_size = mem::size_of::(); + let ptr = unsafe { Unique::new(malloc(cap * elem_size) as *mut T) }; + RawVec { ptr: ptr, cap: cap } + } + + fn grow(&mut self) { + let elem_size = mem::size_of::(); + let new_cap = 2 * self.cap; + let ptr = sized_realloc( + self.ptr.as_ptr() as *mut _, + self.cap * elem_size, + new_cap * elem_size, + ); + + self.ptr = Unique::new(ptr as *mut _); + self.cap = new_cap; + } +} + +#[cfg(verifier = "smack")] +impl Drop for RawVec { + fn drop(&mut self) { + unsafe { free(self.ptr.ptr as *mut _) }; + } +} + +#[cfg(verifier = "smack")] +pub struct Vec { + buf: RawVec, + len: usize, +} + +#[cfg(verifier = "smack")] +impl Vec { + fn ptr(&self) -> *mut T { + self.buf.ptr.as_ptr() + } + + #[allow(dead_code)] + fn cap(&self) -> usize { + self.buf.cap + } + + pub fn new() -> Self { + Vec { + buf: RawVec::new(), + len: 0, + } + } + + #[allow(dead_code)] + pub fn with_capacity(cap: usize) -> Self { + Vec { + buf: RawVec::new_with_capacity(cap), + len: 0, + } + } + + #[allow(dead_code)] + pub fn push(&mut self, elem: T) { + if self.len == self.cap() { + self.buf.grow(); + } + + unsafe { + ptr::write(self.ptr().offset(self.len as isize), elem); + } + + self.len += 1; + } + + #[allow(dead_code)] + pub fn pop(&mut self) -> Option { + if self.len == 0 { + None + } else { + self.len -= 1; + unsafe { Some(ptr::read(self.ptr().offset(self.len as isize))) } + } + } + + #[allow(dead_code)] + pub fn append(&mut self, other: &mut Vec) { + let mut i: usize = 0; + let olen = other.len(); + let mut drain = Vec::new(); + while i < olen { + drain.push(other.pop().unwrap()); + i += 1; + } + // Empty other + i = 0; + while i < olen { + self.push(drain.pop().unwrap()); + i += 1; + } + } + + #[allow(dead_code)] + pub fn insert(&mut self, index: usize, elem: T) { + assert!(index <= self.len); + if self.cap() == self.len { + self.buf.grow(); + } + + unsafe { + if index < self.len { + ptr::copy( + self.ptr().offset(index as isize), + self.ptr().offset(index as isize + 1), + self.len - index, + ); + } + ptr::write(self.ptr().offset(index as isize), elem); + self.len += 1; + } + } + + #[allow(dead_code)] + pub fn remove(&mut self, index: usize) -> T { + assert!(index < self.len); + unsafe { + self.len -= 1; + let result = ptr::read(self.ptr().offset(index as isize)); + ptr::copy( + self.ptr().offset(index as isize + 1), + self.ptr().offset(index as isize), + self.len - index, + ); + result + } + } + + #[allow(dead_code)] + pub fn into_iter(self) -> IntoIter { + unsafe { + let iter = RawValIter::new(&self); + let buf = ptr::read(&self.buf); + mem::forget(self); + + IntoIter { + iter: iter, + _buf: buf, + } + } + } + #[allow(dead_code)] + pub fn len(&self) -> usize { + self.len + } +} + +#[cfg(verifier = "smack")] +impl Default for Vec { + fn default() -> Self { + Vec::new() + } +} + +#[cfg(verifier = "smack")] +impl Drop for Vec { + fn drop(&mut self) { + while let Some(_) = self.pop() {} + // allocation is handled by RawVec + } +} + +#[cfg(verifier = "smack")] +impl Deref for Vec { + type Target = [T]; + fn deref(&self) -> &[T] { + unsafe { ::std::slice::from_raw_parts(self.buf.ptr.ptr, self.len) } + } +} + +#[cfg(verifier = "smack")] +impl DerefMut for Vec { + fn deref_mut(&mut self) -> &mut [T] { + unsafe { ::std::slice::from_raw_parts_mut(self.buf.ptr.ptr as *mut T, self.len) } + } +} + +#[cfg(verifier = "smack")] +struct RawValIter { + start: *const T, + end: *const T, +} + +#[cfg(verifier = "smack")] +impl RawValIter { + unsafe fn new(slice: &[T]) -> Self { + RawValIter { + start: slice.as_ptr(), + end: if mem::size_of::() == 0 { + ((slice.as_ptr() as usize) + slice.len()) as *const _ + } else if slice.len() == 0 { + slice.as_ptr() + } else { + slice.as_ptr().offset(slice.len() as isize) + }, + } + } +} + +#[cfg(verifier = "smack")] +impl Iterator for RawValIter { + type Item = T; + fn next(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + let result = ptr::read(self.start); + self.start = if mem::size_of::() == 0 { + (self.start as usize + 1) as *const _ + } else { + self.start.offset(1) + }; + Some(result) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let elem_size = mem::size_of::(); + let len = + (self.end as usize - self.start as usize) / if elem_size == 0 { 1 } else { elem_size }; + (len, Some(len)) + } +} + +#[cfg(verifier = "smack")] +impl DoubleEndedIterator for RawValIter { + fn next_back(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + self.end = if mem::size_of::() == 0 { + (self.end as usize - 1) as *const _ + } else { + self.end.offset(-1) + }; + Some(ptr::read(self.end)) + } + } + } +} + +#[cfg(verifier = "smack")] +pub struct IntoIter { + _buf: RawVec, // we don't actually care about this. Just need it to live. + iter: RawValIter, +} + +#[cfg(verifier = "smack")] +impl Iterator for IntoIter { + type Item = T; + fn next(&mut self) -> Option { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[cfg(verifier = "smack")] +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} + +#[cfg(verifier = "smack")] +impl Drop for IntoIter { + fn drop(&mut self) { + for _ in &mut *self {} + } +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! vec { + ( $val:expr ; $count:expr ) => + ({ + let mut result = Vec::new(); + let mut i = 0u64; + while i < $count { + result.push($val); + i += 1; + } + result + }); + ( $( $xs:expr ),* ) => { + { + let mut result = Vec::new(); + $( + result.push($xs); + )* + result + } + }; +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +pub struct Box { + ptr: Unique, +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +impl Box { + pub fn new(item: T) -> Box { + let elem_size = mem::size_of::(); + let ptr = unsafe { Unique::new(malloc(elem_size) as *mut T) }; + unsafe { ptr::write(ptr.as_ptr().offset(0), item) }; + Box { ptr: ptr } + } +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +impl Deref for Box { + type Target = T; + fn deref(&self) -> &Self::Target { + unsafe { mem::transmute::<*mut T, &T>(self.ptr.as_ptr()) } + } +} diff --git a/smack/src/smack.c b/smack/src/smack.c new file mode 100644 index 000000000..c83d68d24 --- /dev/null +++ b/smack/src/smack.c @@ -0,0 +1,539 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +#include +#include +#include +#include +#include + +/** + * The SMACK "prelude" definitions + * + * TODO add more documentation + * + * NOTES ON MEMORY MODELS + * + * 1. addresses are (unbounded) integers + * 2. one unbounded integer is stored at each address + * 3. (NO-REUSE only) heap addresses are allocated in a strictly increasing + * fashion + * 4. (NO-REUSE only) freed (heap) addresses are never reallocated + * 5. the address space is partitioned as follows + * + * Address A Allocation + * --------- ---------- + * A > 0 Heap + * A = 0 Not allocated (null) + * $GLOBALS_BOTTOM <= A < 0 Static (global storage) + * $GLOBALS_BOTTOM - 32768 <= A < $GLOBALS_BOTTOM Not allocated (padding) + * $EXTERNS_BOTTOM <= A < $GLOBALS_BOTTOM - 32768 External globals + * A < $EXTERNS_BOTTOM Objects returned from + * external functions + * + */ + +void __VERIFIER_assume(int x) { +#if !RUST_EXEC + __SMACK_dummy(x); + __SMACK_code("assume @ != $0;", x); +#endif +} + +#ifndef CUSTOM_VERIFIER_ASSERT +void __VERIFIER_assert(int x) { +#if !MEMORY_SAFETY && !SIGNED_INTEGER_OVERFLOW_CHECK && !RUST_EXEC + __SMACK_dummy(x); + __SMACK_code("assert @ != $0;", x); +#endif +} +#endif + +void __SMACK_check_overflow(int flag) { + __SMACK_dummy(flag); + __SMACK_code("assert {:overflow} @ == $0;", flag); +} + +char __VERIFIER_nondet_char(void) { + char x = __SMACK_nondet_char(); + __VERIFIER_assume(x >= SCHAR_MIN && x <= SCHAR_MAX); + return x; +} + +signed char __VERIFIER_nondet_signed_char(void) { + signed char x = __SMACK_nondet_signed_char(); + __VERIFIER_assume(x >= SCHAR_MIN && x <= SCHAR_MAX); + return x; +} + +unsigned char __VERIFIER_nondet_unsigned_char(void) { + unsigned char x = __SMACK_nondet_unsigned_char(); + __VERIFIER_assume(x >= 0 && x <= UCHAR_MAX); + return x; +} + +short __VERIFIER_nondet_short(void) { + short x = __SMACK_nondet_short(); + __VERIFIER_assume(x >= SHRT_MIN && x <= SHRT_MAX); + return x; +} + +signed short __VERIFIER_nondet_signed_short(void) { + signed short x = __SMACK_nondet_signed_short(); + __VERIFIER_assume(x >= SHRT_MIN && x <= SHRT_MAX); + return x; +} + +signed short int __VERIFIER_nondet_signed_short_int(void) { + signed short int x = __SMACK_nondet_signed_short_int(); + __VERIFIER_assume(x >= SHRT_MIN && x <= SHRT_MAX); + return x; +} + +unsigned short __VERIFIER_nondet_unsigned_short(void) { + unsigned short x = __SMACK_nondet_unsigned_short(); + __VERIFIER_assume(x >= 0 && x <= USHRT_MAX); + return x; +} + +unsigned short int __VERIFIER_nondet_unsigned_short_int(void) { + unsigned short int x = __SMACK_nondet_unsigned_short_int(); + __VERIFIER_assume(x >= 0 && x <= USHRT_MAX); + return x; +} + +int __VERIFIER_nondet_int(void) { + int x = __SMACK_nondet_int(); + __VERIFIER_assume(x >= INT_MIN && x <= INT_MAX); + return x; +} + +signed int __VERIFIER_nondet_signed_int(void) { + signed int x = __SMACK_nondet_signed_int(); + __VERIFIER_assume(x >= INT_MIN && x <= INT_MAX); + return x; +} + +unsigned __VERIFIER_nondet_unsigned(void) { + unsigned x = __SMACK_nondet_unsigned(); + unsigned min = __SMACK_nondet_unsigned(); + unsigned max = __SMACK_nondet_unsigned(); + __VERIFIER_assume(min == 0 && max >= UINT_MAX && max <= UINT_MAX); + __VERIFIER_assume(x >= min && x <= max); + return x; +} + +unsigned int __VERIFIER_nondet_unsigned_int(void) { + unsigned int x = __SMACK_nondet_unsigned_int(); + unsigned int min = __SMACK_nondet_unsigned_int(); + unsigned int max = __SMACK_nondet_unsigned_int(); + __VERIFIER_assume(min == 0 && max >= UINT_MAX && max <= UINT_MAX); + __VERIFIER_assume(x >= min && x <= max); + return x; +} + +long __VERIFIER_nondet_long(void) { + long x = __SMACK_nondet_long(); + __VERIFIER_assume(x >= LONG_MIN && x <= LONG_MAX); + return x; +} + +long int __VERIFIER_nondet_long_int(void) { + long int x = __SMACK_nondet_long_int(); + __VERIFIER_assume(x >= LONG_MIN && x <= LONG_MAX); + return x; +} + +signed long __VERIFIER_nondet_signed_long(void) { + signed long x = __SMACK_nondet_signed_long(); + __VERIFIER_assume(x >= LONG_MIN && x <= LONG_MAX); + return x; +} + +signed long int __VERIFIER_nondet_signed_long_int(void) { + signed long int x = __SMACK_nondet_signed_long_int(); + __VERIFIER_assume(x >= LONG_MIN && x <= LONG_MAX); + return x; +} + +unsigned long __VERIFIER_nondet_unsigned_long(void) { + unsigned long x = __SMACK_nondet_unsigned_long(); + unsigned long min = __SMACK_nondet_unsigned_long(); + unsigned long max = __SMACK_nondet_unsigned_long(); + __VERIFIER_assume(min == 0 && max >= ULONG_MAX && max <= ULONG_MAX); + __VERIFIER_assume(x >= min && x <= max); + return x; +} + +unsigned long int __VERIFIER_nondet_unsigned_long_int(void) { + unsigned long int x = __SMACK_nondet_unsigned_long_int(); + unsigned long int min = __SMACK_nondet_unsigned_long_int(); + unsigned long int max = __SMACK_nondet_unsigned_long_int(); + __VERIFIER_assume(min == 0 && max >= ULONG_MAX && max <= ULONG_MAX); + __VERIFIER_assume(x >= min && x <= max); + return x; +} + +long long __VERIFIER_nondet_long_long(void) { + long long x = __SMACK_nondet_long_long(); + __VERIFIER_assume(x >= LLONG_MIN && x <= LLONG_MAX); + return x; +} + +long long int __VERIFIER_nondet_long_long_int(void) { + long long int x = __SMACK_nondet_long_long_int(); + __VERIFIER_assume(x >= LLONG_MIN && x <= LLONG_MAX); + return x; +} + +signed long long __VERIFIER_nondet_signed_long_long(void) { + signed long long x = __SMACK_nondet_signed_long_long(); + __VERIFIER_assume(x >= LLONG_MIN && x <= LLONG_MAX); + return x; +} + +signed long long int __VERIFIER_nondet_signed_long_long_int(void) { + signed long long int x = __SMACK_nondet_signed_long_long_int(); + __VERIFIER_assume(x >= LLONG_MIN && x <= LLONG_MAX); + return x; +} + +unsigned long long __VERIFIER_nondet_unsigned_long_long(void) { + unsigned long long x = __SMACK_nondet_unsigned_long_long(); + unsigned long long min = __SMACK_nondet_unsigned_long_long(); + unsigned long long max = __SMACK_nondet_unsigned_long_long(); + __VERIFIER_assume(min == 0 && max >= ULLONG_MAX && max <= ULLONG_MAX); + __VERIFIER_assume(x >= min && x <= max); + return x; +} + +unsigned long long int __VERIFIER_nondet_unsigned_long_long_int(void) { + unsigned long long int x = __SMACK_nondet_unsigned_long_long_int(); + unsigned long long int min = __SMACK_nondet_unsigned_long_long_int(); + unsigned long long int max = __SMACK_nondet_unsigned_long_long_int(); + __VERIFIER_assume(min == 0 && max >= ULLONG_MAX && max <= ULLONG_MAX); + __VERIFIER_assume(x >= min && x <= max); + return x; +} + +// Used in SVCCOMP benchmarks + +_Bool __VERIFIER_nondet_bool(void) { + _Bool x = (_Bool)__VERIFIER_nondet_int(); + __VERIFIER_assume(x == 0 || x == 1); + return x; +} + +unsigned char __VERIFIER_nondet_uchar(void) { + unsigned char x = __VERIFIER_nondet_unsigned_char(); + return x; +} + +unsigned short __VERIFIER_nondet_ushort(void) { + unsigned short x = __VERIFIER_nondet_unsigned_short(); + return x; +} + +unsigned int __VERIFIER_nondet_uint(void) { + unsigned int x = __VERIFIER_nondet_unsigned_int(); + return x; +} + +unsigned long __VERIFIER_nondet_ulong(void) { + unsigned long x = __VERIFIER_nondet_unsigned_long(); + return x; +} + +void *__VERIFIER_nondet_pointer(void) { return __VERIFIER_nondet(); } + +void __SMACK_dummy(int v) { __SMACK_code("assume true;"); } + +#define D(d) __SMACK_top_decl(d) + +void __SMACK_decls(void) { + // Memory debugging symbols + D("type $mop;"); + D("procedure boogie_si_record_mop(m: $mop);"); + D("const $MOP: $mop;"); + + D("var $exn: bool;"); + D("var $exnv: int;"); + + // Concurrency primitives + D("procedure corral_atomic_begin();"); + D("procedure corral_atomic_end();"); + + D("procedure $alloc(n: ref) returns (p: ref)\n" + "{\n" + " call corral_atomic_begin();\n" + " call p := $$alloc(n);\n" + " call corral_atomic_end();\n" + "}\n"); + +#if MEMORY_SAFETY + __SMACK_dummy((int)__SMACK_check_memory_safety); + D("implementation __SMACK_check_memory_safety(p: ref, size: ref)\n" + "{\n" + " assert {:valid_deref} $Alloc[$base(p)];\n" + " assert {:valid_deref} $sle.ref.bool($base(p), p);\n" +#if MEMORY_MODEL_NO_REUSE_IMPLS + " assert {:valid_deref} $sle.ref.bool($add.ref(p, size), " + "$add.ref($base(p), $Size($base(p))));\n" +#elif MEMORY_MODEL_REUSE + " assert {:valid_deref} $sle.ref.bool($add.ref(p, size), " + "$add.ref($base(p), $Size[$base(p)]));\n" +#else + " assert {:valid_deref} $sle.ref.bool($add.ref(p, size), " + "$add.ref($base(p), $Size($base(p))));\n" +#endif + "}\n"); + + D("function $base(ref) returns (ref);"); + D("var $allocatedCounter: int;\n"); + + D("procedure $malloc(n: ref) returns (p: ref)\n" + "modifies $allocatedCounter;\n" + "{\n" + " call corral_atomic_begin();\n" + " if ($ne.ref.bool(n, $0.ref)) {\n" + " $allocatedCounter := $allocatedCounter + 1;\n" + " }\n" + " call p := $$alloc(n);\n" + " call corral_atomic_end();\n" + "}\n"); + +#if MEMORY_MODEL_NO_REUSE_IMPLS + D("var $Alloc: [ref] bool;"); + D("function $Size(ref) returns (ref);"); + D("var $CurrAddr:ref;\n"); + + // LLVM does not allocated globals explicitly. Hence, we do it in our prelude + // before the program starts using the $galloc procedure. + D("procedure $galloc(base_addr: ref, size: ref)\n" + "{\n" + " assume $Size(base_addr) == size;\n" + " assume (forall addr: ref :: {$base(addr)} $sle.ref.bool(base_addr, " + "addr) && $slt.ref.bool(addr, $add.ref(base_addr, size)) ==> $base(addr) " + "== base_addr);\n" + " $Alloc[base_addr] := true;\n" + "}\n"); + + D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref)\n" + "modifies $Alloc, $CurrAddr;\n" + "{\n" + " assume $sle.ref.bool($0.ref, n);\n" + " if ($slt.ref.bool($0.ref, n)) {\n" + " p := $CurrAddr;\n" + " havoc $CurrAddr;\n" + " assume $sge.ref.bool($sub.ref($CurrAddr, n), p);\n" + " assume $sgt.ref.bool($CurrAddr, $0.ref) && $slt.ref.bool($CurrAddr, " + "$MALLOC_TOP);\n" + " assume $Size(p) == n;\n" + " assume (forall q: ref :: {$base(q)} $sle.ref.bool(p, q) && " + "$slt.ref.bool(q, $add.ref(p, n)) ==> $base(q) == p);\n" + " $Alloc[p] := true;\n" + " } else {\n" + " p := $0.ref;\n" + " }\n" + "}\n"); + + D("procedure $free(p: ref)\n" + "modifies $Alloc, $allocatedCounter;\n" + "{\n" + " call corral_atomic_begin();\n" + " if ($ne.ref.bool(p, $0.ref)) {\n" + " assert {:valid_free} $eq.ref.bool($base(p), p);\n" + " assert {:valid_free} $Alloc[p];\n" + " assert {:valid_free} $slt.ref.bool($0.ref, p);\n" + " $Alloc[p] := false;\n" + " $allocatedCounter := $allocatedCounter - 1;\n" + " }\n" + " call corral_atomic_end();\n" + "}\n"); + +#elif MEMORY_MODEL_REUSE // can reuse previously-allocated and freed addresses + D("var $Alloc: [ref] bool;"); + D("var $Size: [ref] ref;\n"); + + // LLVM does not allocated globals explicitly. Hence, we do it in our prelude + // before the program starts using the $galloc procedure. + D("procedure $galloc(base_addr: ref, size: ref);\n" + "modifies $Alloc, $Size;\n" + "ensures $Size[base_addr] == size;\n" + "ensures (forall addr: ref :: {$base(addr)} $sle.ref.bool(base_addr, addr) " + "&& $slt.ref.bool(addr, $add.ref(base_addr, size)) ==> $base(addr) == " + "base_addr);\n" + "ensures $Alloc[base_addr];\n" + "ensures (forall q: ref :: {$Size[q]} q != base_addr ==> $Size[q] == " + "old($Size[q]));\n" + "ensures (forall q: ref :: {$Alloc[q]} q != base_addr ==> $Alloc[q] == " + "old($Alloc[q]));\n"); + + D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref);\n" + "modifies $Alloc, $Size;\n" + "ensures $sle.ref.bool($0.ref, n);\n" + "ensures $slt.ref.bool($0.ref, n) ==> $slt.ref.bool($0.ref, p) && " + "$slt.ref.bool(p, $sub.ref($MALLOC_TOP, n));\n" + "ensures $eq.ref.bool(n, $0.ref) ==> p == $0.ref;\n" + "ensures !old($Alloc[p]);\n" + "ensures (forall q: ref :: old($Alloc[q]) ==> ($slt.ref.bool($add.ref(p, " + "n), q) || $slt.ref.bool($add.ref(q, $Size[q]), p)));\n" + "ensures $Alloc[p];\n" + "ensures $Size[p] == n;\n" + "ensures (forall q: ref :: {$Size[q]} q != p ==> $Size[q] == " + "old($Size[q]));\n" + "ensures (forall q: ref :: {$Alloc[q]} q != p ==> $Alloc[q] == " + "old($Alloc[q]));\n" + "ensures (forall q: ref :: {$base(q)} $sle.ref.bool(p, q) && " + "$slt.ref.bool(q, $add.ref(p, n)) ==> $base(q) == p);\n"); + + D("procedure $free(p: ref);\n" + "modifies $Alloc, $allocatedCounter;\n" + "requires $eq.ref.bool(p, $0.ref) || ($eq.ref.bool($base(p), p) && " + "$Alloc[p]);\n" + "requires $slt.ref.bool($0.ref, p);\n" + "ensures $ne.ref.bool(p, $0.ref) ==> !$Alloc[p];\n" + "ensures $ne.ref.bool(p, $0.ref) ==> (forall q: ref :: {$Alloc[q]} q != p " + "==> $Alloc[q] == old($Alloc[q]));\n" + "ensures $ne.ref.bool(p, $0.ref) ==> $allocatedCounter == " + "old($allocatedCounter) - 1;\n"); + +#else // NO_REUSE does not reuse previously-allocated addresses + D("var $Alloc: [ref] bool;"); + D("function $Size(ref) returns (ref);"); + D("var $CurrAddr:ref;\n"); + + // LLVM does not allocated globals explicitly. Hence, we do it in our prelude + // before the program starts using the $galloc procedure. + D("procedure $galloc(base_addr: ref, size: ref);\n" + "modifies $Alloc;\n" + "ensures $Size(base_addr) == size;\n" + "ensures (forall addr: ref :: {$base(addr)} $sle.ref.bool(base_addr, addr) " + "&& $slt.ref.bool(addr, $add.ref(base_addr, size)) ==> $base(addr) == " + "base_addr);\n" + "ensures $Alloc[base_addr];\n" + "ensures (forall q: ref :: {$Alloc[q]} q != base_addr ==> $Alloc[q] == " + "old($Alloc[q]));\n"); + + D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref);\n" + "modifies $Alloc, $CurrAddr;\n" + "ensures $sle.ref.bool($0.ref, n);\n" + "ensures $slt.ref.bool($0.ref, n) ==> $sge.ref.bool($sub.ref($CurrAddr, " + "n), old($CurrAddr)) && p == old($CurrAddr);\n" + "ensures $sgt.ref.bool($CurrAddr, $0.ref) && $slt.ref.bool($CurrAddr, " + "$MALLOC_TOP);\n" + "ensures $slt.ref.bool($0.ref, n) ==> $Size(p) == n;\n" + "ensures $slt.ref.bool($0.ref, n) ==> (forall q: ref :: {$base(q)} " + "$sle.ref.bool(p, q) && $slt.ref.bool(q, $add.ref(p, n)) ==> $base(q) == " + "p);\n" + "ensures $slt.ref.bool($0.ref, n) ==> $Alloc[p];\n" + "ensures $eq.ref.bool(n, $0.ref) ==> old($CurrAddr) == $CurrAddr && p == " + "$0.ref;\n" + "ensures $eq.ref.bool(n, $0.ref)==> $Alloc[p] == old($Alloc)[p];\n" + "ensures (forall q: ref :: {$Alloc[q]} q != p ==> $Alloc[q] == " + "old($Alloc[q]));\n"); + + D("procedure $free(p: ref);\n" + "modifies $Alloc, $allocatedCounter;\n" + "requires $eq.ref.bool(p, $0.ref) || ($eq.ref.bool($base(p), p) && " + "$Alloc[p]);\n" + "requires $slt.ref.bool($0.ref, p);\n" + "ensures $ne.ref.bool(p, $0.ref) ==> !$Alloc[p];\n" + "ensures $ne.ref.bool(p, $0.ref) ==> (forall q: ref :: {$Alloc[q]} q != p " + "==> $Alloc[q] == old($Alloc[q]));\n" + "ensures $ne.ref.bool(p, $0.ref) ==> $allocatedCounter == " + "old($allocatedCounter) - 1;\n"); +#endif + +#else + D("procedure $malloc(n: ref) returns (p: ref)\n" + "{\n" + " call corral_atomic_begin();\n" + " call p := $$alloc(n);\n" + " call corral_atomic_end();\n" + "}\n"); + +#if MEMORY_MODEL_NO_REUSE_IMPLS + D("var $CurrAddr:ref;\n"); + + D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref)\n" + "modifies $CurrAddr;\n" + "{\n" + " assume $sge.ref.bool(n, $0.ref);\n" + " if ($sgt.ref.bool(n, $0.ref)) {\n" + " p := $CurrAddr;\n" + " havoc $CurrAddr;\n" + " assume $sge.ref.bool($sub.ref($CurrAddr, n), p);\n" + " assume $sgt.ref.bool($CurrAddr, $0.ref) && $slt.ref.bool($CurrAddr, " + "$MALLOC_TOP);\n" + " } else {\n" + " p := $0.ref;\n" + " }\n" + "}\n"); + + D("procedure $free(p: ref);\n"); + +#elif MEMORY_MODEL_REUSE // can reuse previously-allocated and freed addresses + D("var $Alloc: [ref] bool;"); + D("var $Size: [ref] ref;\n"); + + D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref);\n" + "modifies $Alloc, $Size;\n" + "ensures $sle.ref.bool($0.ref, n);\n" + "ensures $slt.ref.bool($0.ref, n) ==> $slt.ref.bool($0.ref, p) && " + "$slt.ref.bool(p, $sub.ref($MALLOC_TOP, n));\n" + "ensures $eq.ref.bool(n, $0.ref) ==> p == $0.ref;\n" + "ensures !old($Alloc[p]);\n" + "ensures (forall q: ref :: old($Alloc[q]) ==> ($slt.ref.bool($add.ref(p, " + "n), q) || $slt.ref.bool($add.ref(q, $Size[q]), p)));\n" + "ensures $Alloc[p];\n" + "ensures $Size[p] == n;\n" + "ensures (forall q: ref :: {$Size[q]} q != p ==> $Size[q] == " + "old($Size[q]));\n" + "ensures (forall q: ref :: {$Alloc[q]} q != p ==> $Alloc[q] == " + "old($Alloc[q]));\n"); + + D("procedure $free(p: ref);\n" + "modifies $Alloc;\n" + "ensures !$Alloc[p];\n" + "ensures (forall q: ref :: {$Alloc[q]} q != p ==> $Alloc[q] == " + "old($Alloc[q]));\n"); + +#else // NO_REUSE does not reuse previously-allocated addresses + D("var $CurrAddr:ref;\n"); + + D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref);\n" + "modifies $CurrAddr;\n" + "ensures $sle.ref.bool($0.ref, n);\n" + "ensures $slt.ref.bool($0.ref, n) ==> $sge.ref.bool($sub.ref($CurrAddr, " + "n), old($CurrAddr)) && p == old($CurrAddr);\n" + "ensures $sgt.ref.bool($CurrAddr, $0.ref) && $slt.ref.bool($CurrAddr, " + "$MALLOC_TOP);\n" + "ensures $eq.ref.bool(n, $0.ref) ==> old($CurrAddr) == $CurrAddr && p == " + "$0.ref;\n"); + + D("procedure $free(p: ref);\n"); +#endif +#endif + +#undef D +} + +#if MEMORY_SAFETY +void __SMACK_check_memory_leak(void) { + __SMACK_code("assert {:valid_memtrack} $allocatedCounter == 0;"); +} +#endif + +void __SMACK_init_func_memory_model(void) { +#if MEMORY_MODEL_NO_REUSE || MEMORY_MODEL_NO_REUSE_IMPLS + __SMACK_code("$CurrAddr := $1024.ref;"); +#endif +#if MEMORY_SAFETY + __SMACK_code("$allocatedCounter := 0;"); +#endif +} + +void __VERIFIER_atomic_begin() { __SMACK_code("call corral_atomic_begin();"); } + +void __VERIFIER_atomic_end() { __SMACK_code("call corral_atomic_end();"); } diff --git a/smack/src/smack.h b/smack/src/smack.h new file mode 100644 index 000000000..19f755c50 --- /dev/null +++ b/smack/src/smack.h @@ -0,0 +1,178 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +#ifndef SMACK_H_ +#define SMACK_H_ +#include + +/** + * The SMACK "prelude" declarations + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef SVCOMP +// Apprently needed by SVCOMP benchmarks +#define __inline +#define __builtin_expect __builtinx_expect +#define __builtin_memcpy __builtinx_memcpy +#define __builtin_va_start __builtinx_va_start +#define __builtin_object_size __builtinx_object_size + +// For handling of va_start macro +void __builtinx_va_start(char *, char *); +#endif + +void __SMACK_code(const char *fmt, ...); +void __SMACK_mod(const char *fmt, ...); +void __SMACK_decl(const char *fmt, ...); +void __SMACK_top_decl(const char *fmt, ...); + +typedef struct smack_value { + void *dummy; +} * smack_value_t; +smack_value_t __SMACK_value(); +smack_value_t __SMACK_values(void *ary, unsigned count); +smack_value_t __SMACK_return_value(void); + +// Sugar for __SMACK_init_func_XXX() +#define __SMACK_INIT(x) void __SMACK_init_func_##x() + +#if MEMORY_SAFETY +// Inserts memory access checks in form of assert to check null pointer access +// and buffer overflow errors +void __SMACK_check_memory_safety(void *, void *) __attribute__((const)); +void __SMACK_check_memory_leak(void); +#endif + +// We need this to enforce that assert/assume are function calls +// with an integer argument (DSA gets confused otherwise) +__attribute__((always_inline)) void __SMACK_dummy(int v); + +void __VERIFIER_assume(int); +#ifndef CUSTOM_VERIFIER_ASSERT +void __VERIFIER_assert(int); +#endif + +#ifndef AVOID_NAME_CONFLICTS +#define assert(EX) \ + do { \ + if (!(EX)) \ + __VERIFIER_assert(0); \ + } while (0) +#define assume(EX) \ + do { \ + if (!(EX)) \ + __VERIFIER_assume(0); \ + } while (0) +#endif + +#define S4(a, b, c, d) a b c d +#define S3(a, b, c) a b c +#define S2(a, b) a b +#define S1(a) a +#define U4(a, b, c, d) a##_##b##_##c##_##d +#define U3(a, b, c) a##_##b##_##c +#define U2(a, b) a##_##b +#define U1(a) a + +#define TY(_1, _2, _3, _4, A, ...) A + +#define S(...) TY(__VA_ARGS__, S4, S3, S2, S1)(__VA_ARGS__) +#define U(...) TY(__VA_ARGS__, U4, U3, U2, U1)(__VA_ARGS__) + +#define NONDET_DECL(P, ty...) S(ty) U(P, U(ty))(void) + +void *__VERIFIER_nondet(void); +NONDET_DECL(__SMACK_nondet, char); +NONDET_DECL(__SMACK_nondet, signed, char); +NONDET_DECL(__SMACK_nondet, unsigned, char); +NONDET_DECL(__SMACK_nondet, short); +NONDET_DECL(__SMACK_nondet, short, int); +NONDET_DECL(__SMACK_nondet, signed, short); +NONDET_DECL(__SMACK_nondet, signed, short, int); +NONDET_DECL(__SMACK_nondet, unsigned, short); +NONDET_DECL(__SMACK_nondet, unsigned, short, int); +NONDET_DECL(__SMACK_nondet, int); +NONDET_DECL(__SMACK_nondet, signed, int); +NONDET_DECL(__SMACK_nondet, unsigned); +NONDET_DECL(__SMACK_nondet, unsigned, int); +NONDET_DECL(__SMACK_nondet, long); +NONDET_DECL(__SMACK_nondet, long, int); +NONDET_DECL(__SMACK_nondet, signed, long); +NONDET_DECL(__SMACK_nondet, signed, long, int); +NONDET_DECL(__SMACK_nondet, unsigned, long); +NONDET_DECL(__SMACK_nondet, unsigned, long, int); +NONDET_DECL(__SMACK_nondet, long, long); +NONDET_DECL(__SMACK_nondet, long, long, int); +NONDET_DECL(__SMACK_nondet, signed, long, long); +NONDET_DECL(__SMACK_nondet, signed, long, long, int); +NONDET_DECL(__SMACK_nondet, unsigned, long, long); +NONDET_DECL(__SMACK_nondet, unsigned, long, long, int); +NONDET_DECL(__VERIFIER_nondet, char); +NONDET_DECL(__VERIFIER_nondet, signed, char); +NONDET_DECL(__VERIFIER_nondet, unsigned, char); +NONDET_DECL(__VERIFIER_nondet, short); +NONDET_DECL(__VERIFIER_nondet, short, int); +NONDET_DECL(__VERIFIER_nondet, signed, short); +NONDET_DECL(__VERIFIER_nondet, signed, short, int); +NONDET_DECL(__VERIFIER_nondet, unsigned, short); +NONDET_DECL(__VERIFIER_nondet, unsigned, short, int); +NONDET_DECL(__VERIFIER_nondet, int); +NONDET_DECL(__VERIFIER_nondet, signed, int); +NONDET_DECL(__VERIFIER_nondet, unsigned); +NONDET_DECL(__VERIFIER_nondet, unsigned, int); +NONDET_DECL(__VERIFIER_nondet, long); +NONDET_DECL(__VERIFIER_nondet, long, int); +NONDET_DECL(__VERIFIER_nondet, signed, long); +NONDET_DECL(__VERIFIER_nondet, signed, long, int); +NONDET_DECL(__VERIFIER_nondet, unsigned, long); +NONDET_DECL(__VERIFIER_nondet, unsigned, long, int); +NONDET_DECL(__VERIFIER_nondet, long, long); +NONDET_DECL(__VERIFIER_nondet, long, long, int); +NONDET_DECL(__VERIFIER_nondet, signed, long, long); +NONDET_DECL(__VERIFIER_nondet, signed, long, long, int); +NONDET_DECL(__VERIFIER_nondet, unsigned, long, long); +NONDET_DECL(__VERIFIER_nondet, unsigned, long, long, int); +NONDET_DECL(__VERIFIER_nondet, float); +NONDET_DECL(__VERIFIER_nondet, double); +NONDET_DECL(__VERIFIER_nondet, long, double); + +#undef S1 +#undef S2 +#undef S3 +#undef S4 +#undef U1 +#undef U2 +#undef U3 +#undef U4 +#undef TY +#undef S +#undef U +#undef NONDET_DECL + +// Used in SVCOMP benchmarks +#ifdef __cplusplus +bool __VERIFIER_nondet_bool(void); +#else +_Bool __VERIFIER_nondet_bool(void); +#endif +unsigned char __VERIFIER_nondet_uchar(void); +unsigned short __VERIFIER_nondet_ushort(void); +unsigned __VERIFIER_nondet_uint(void); +unsigned long __VERIFIER_nondet_ulong(void); +void *__VERIFIER_nondet_pointer(void); + +void __SMACK_decls(void); + +// Concurrency helper functions +void __VERIFIER_atomic_begin(); +void __VERIFIER_atomic_end(); + +#ifdef __cplusplus +} +#endif + +#endif /*SMACK_H_*/ From d195b9d233586cd3cfde350100d538f07554dbd4 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Tue, 18 Aug 2020 14:50:30 -0600 Subject: [PATCH 002/109] Prototype rust wrapper --- bin/build.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bin/build.sh b/bin/build.sh index 5751c9a3d..215c4e8e9 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -201,6 +201,11 @@ linux-@(ubuntu|neon)-18*) DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev" ;; +linux-@(ubuntu|neon)-20*) + Z3_DOWNLOAD_LINK="https://github.com/Z3Prover/z3/releases/download/z3-${Z3_VERSION}/z3-${Z3_VERSION}-x64-ubuntu-16.04.zip" + DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev" + ;; + *) puts "Distribution ${distro} not supported. Manual installation required." exit 1 @@ -237,7 +242,7 @@ if [ ${INSTALL_DEPENDENCIES} -eq 1 ] && [ "$TRAVIS" != "true" ] ; then sudo zypper --non-interactive install ${DEPENDENCIES} ;; - linux-@(ubuntu|neon)-1[68]*) + linux-@(ubuntu|neon)-@(1[68]|20)*) RELEASE_VERSION=$(get-platform-trim "$(lsb_release -r)" | awk -F: '{print $2;}') case "$RELEASE_VERSION" in 16*) @@ -246,6 +251,9 @@ if [ ${INSTALL_DEPENDENCIES} -eq 1 ] && [ "$TRAVIS" != "true" ] ; then 18*) UBUNTU_CODENAME="bionic" ;; + 20*) + UBUNTU_CODENAME="focal" + ;; *) puts "Release ${RELEASE_VERSION} for ${distro} not supported. Dependencies must be installed manually." exit 1 From 50d86a8d124e4fab588e26236fe113f4d7eeeb1d Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Tue, 18 Aug 2020 14:53:29 -0600 Subject: [PATCH 003/109] Prototype wrapper --- share/smack/smack-rust.py | 177 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100755 share/smack/smack-rust.py diff --git a/share/smack/smack-rust.py b/share/smack/smack-rust.py new file mode 100755 index 000000000..2f640836c --- /dev/null +++ b/share/smack/smack-rust.py @@ -0,0 +1,177 @@ +#! /usr/bin/env python3 + +import sys +import os +import subprocess + +# rustc --help -v +# +# Usage: rustc [OPTIONS] INPUT +# +# Options: +# -h, --help Display this message +# --cfg SPEC Configure the compilation environment +# -L [KIND=]PATH Add a directory to the library search path. The +# optional KIND can be one of dependency, crate, native, +# framework, or all (the default). +# -l [KIND=]NAME Link the generated crate(s) to the specified native +# library NAME. The optional KIND can be one of +# static, framework, or dylib (the default). +# --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] +# Comma separated list of types of crates +# for the compiler to emit +# --crate-name NAME +# Specify the name of the crate being built +# --edition 2015|2018 +# Specify which edition of the compiler to use when +# compiling code. +# --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] +# Comma separated list of types of output for the +# compiler to emit +# --print [crate-name|file-names|sysroot|cfg|target-list|target-cpus|target-features|relocation-models|code-models|tls-models|target-spec-json|native-static-libs] +# Compiler information to print on stdout +# -g Equivalent to -C debuginfo=2 +# -O Equivalent to -C opt-level=2 +# -o FILENAME Write output to +# --out-dir DIR Write output to compiler-chosen filename in +# --explain OPT Provide a detailed explanation of an error message +# --test Build a test harness +# --target TARGET Target triple for which the code is compiled +# -W, --warn OPT Set lint warnings +# -A, --allow OPT Set lint allowed +# -D, --deny OPT Set lint denied +# -F, --forbid OPT Set lint forbidden +# --cap-lints LEVEL +# Set the most restrictive lint level. More restrictive +# lints are capped at this level +# -C, --codegen OPT[=VALUE] +# Set a codegen option +# -V, --version Print version info and exit +# -v, --verbose Use verbose output +# --extern NAME=PATH +# Specify where an external rust library is located +# --extern-private NAME=PATH +# Specify where an extern rust library is located, +# marking it as a private dependency +# --sysroot PATH Override the system root +# --error-format human|json|short +# How errors and other messages are produced +# --color auto|always|never +# Configure coloring of output: +# auto = colorize, if output goes to a tty (default); +# always = always colorize output; +# never = never colorize output +# --remap-path-prefix FROM=TO +# Remap source names in all output (compiler messages +# and output files) +# +# Additional help: +# -C help Print codegen options +# -W help Print 'lint' options and default settings +# -Z help Print unstable compiler options + +class Arguments: + def __init__(self): + self.crate_type = set() + self.emit = set() + self.codegen = dict() + self.others = [] + + def __str__(self): + return " ".join(self.str_list()) + + def str_list(self): + res = [] + if len(self.emit): + res.append('--emit='+','.join(self.emit)) + if len(self.crate_type): + res.extend(['--crate-type', ','.join(self.crate_type)]) + for opt in self.codegen.items(): + if opt[1] is not None: + res.extend(['-C', "{}={}".format(opt[0],opt[1])]) + else: + res.extend(['-C', "{}".format(opt[0],opt[1])]) + res.extend(self.others) + return res + + def get_codegen_opts(self): + res = dict() + for opt in self.codegen: + k,v = opt.split('=') + res[k] = v + return res + + def get_smack_form(self): + crate_type = self.crate_type + emit = self.emit + codegen = self.codegen + others = self.others + codegen['opt-level'] = '0' + others.aappend('-g') + +def has_equals(arg): + if '=' in arg: + s = arg.split('=') + return s[-1] + return None + +def parse_args(argv = sys.argv): + i = 0 + args = Arguments() + while i < len(argv): + arg = argv[i] + # --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] + if arg.startswith('--crate-type'): + opt = has_equals(arg) + if not opt: + i += 1 + opt = argv[i] + for op in opt.split(','): + args.crate_type.add(op) + # --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] + elif arg.startswith('--emit'): + opt = has_equals(arg) + if not opt: + i += 1 + opt = argv[i] + for op in opt.split(','): + args.emit.add(op) + elif arg in ('-g', '-O'): + # Ignore + pass + elif arg == '-C': + i += 1 + if '=' in argv[i]: + k,v = argv[i].split('=') + else: + k = argv[i] + v = None + args.codegen[k] = v + else: + args.others.append(arg) + i += 1 + return args + +args = parse_args(sys.argv[1:]) + +#print(args.get_codegen_opts()) + +#print(args.str_list()) + +autocfg=False +for i in args.str_list(): + if 'autocfg' in i: + autocfg=True + break + +if autocfg: + with open('/Users/marksb/src/smack/half-rs/newlog.txt', 'a') as f: + f.write('original: rustc ' + ' '.join(sys.argv[1:]) + '\n') + f.write('rewrite: rustc ' + ' '.join(args.str_list()) + '\n') + f.write('-'*80 + '\n') + + +proc = subprocess.run(['rustc'] + args.str_list(), env=os.environ) +#proc = subprocess.run(['rustc'] + sys.argv[1:], env=os.environ) + +exit(proc.returncode) From def4688504e0c2dac5cb9bfd3024b5b21a3dcc7c Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 00:54:12 -0600 Subject: [PATCH 004/109] Improvements --- share/smack/{smack-rust.py => smack-rustc.py} | 142 +++++++----------- 1 file changed, 56 insertions(+), 86 deletions(-) rename share/smack/{smack-rust.py => smack-rustc.py} (65%) diff --git a/share/smack/smack-rust.py b/share/smack/smack-rustc.py similarity index 65% rename from share/smack/smack-rust.py rename to share/smack/smack-rustc.py index 2f640836c..86f38eb89 100755 --- a/share/smack/smack-rust.py +++ b/share/smack/smack-rustc.py @@ -4,7 +4,7 @@ import os import subprocess -# rustc --help -v +# $ rustc --help -v # # Usage: rustc [OPTIONS] INPUT # @@ -70,108 +70,78 @@ # -W help Print 'lint' options and default settings # -Z help Print unstable compiler options -class Arguments: - def __init__(self): - self.crate_type = set() - self.emit = set() - self.codegen = dict() - self.others = [] +def smack_overrides(args): + args['codegen_opts'].update({'debuginfo': '2', + 'opt-level': '0', + 'no-prepopulate-passes': None, + 'passes':'name-anon-globals'}) - def __str__(self): - return " ".join(self.str_list()) - def str_list(self): - res = [] - if len(self.emit): - res.append('--emit='+','.join(self.emit)) - if len(self.crate_type): - res.extend(['--crate-type', ','.join(self.crate_type)]) - for opt in self.codegen.items(): - if opt[1] is not None: - res.extend(['-C', "{}={}".format(opt[0],opt[1])]) - else: - res.extend(['-C', "{}".format(opt[0],opt[1])]) - res.extend(self.others) - return res - - def get_codegen_opts(self): - res = dict() - for opt in self.codegen: - k,v = opt.split('=') - res[k] = v - return res - - def get_smack_form(self): - crate_type = self.crate_type - emit = self.emit - codegen = self.codegen - others = self.others - codegen['opt-level'] = '0' - others.aappend('-g') - -def has_equals(arg): - if '=' in arg: - s = arg.split('=') - return s[-1] - return None - +def process_equals_arg(argv, i): + if '=' in argv[i]: + arg = argv[i].split('=')[-1] + else: + assert(len(argv) > i+1) + i += 1 + arg = argv[i] + return set(arg.split(',')), i + def parse_args(argv = sys.argv): + crate_types = set() + emit_types = {'llvm-bc'} + other_args = [] + codegen_opts = dict() i = 0 - args = Arguments() while i < len(argv): arg = argv[i] # --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] - if arg.startswith('--crate-type'): - opt = has_equals(arg) - if not opt: - i += 1 - opt = argv[i] - for op in opt.split(','): - args.crate_type.add(op) + if False and arg.startswith('--crate-type'): + args, i = process_equals_arg(argv,i) + crate_types |= args # --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] elif arg.startswith('--emit'): - opt = has_equals(arg) - if not opt: + args, i = process_equals_arg(argv,i) + emit_types |= args + # codegen options -C opt, -C opt=opt -Copt + elif arg.startswith('-C'): + if arg == '-C': i += 1 - opt = argv[i] - for op in opt.split(','): - args.emit.add(op) - elif arg in ('-g', '-O'): - # Ignore - pass - elif arg == '-C': - i += 1 - if '=' in argv[i]: - k,v = argv[i].split('=') + arg = argv[i] else: - k = argv[i] - v = None - args.codegen[k] = v + arg = arg[2:] + + if len(arg.split('=')) == 2: + a, v = arg.split('=') + else: + a, v = arg, None + codegen_opts[a] = v else: - args.others.append(arg) + other_args.append(argv[i]) i += 1 - return args - + return {'crate_types': crate_types, + 'other_args' : other_args, + 'emit_types': emit_types, + 'codegen_opts': codegen_opts} + args = parse_args(sys.argv[1:]) - -#print(args.get_codegen_opts()) - -#print(args.str_list()) -autocfg=False -for i in args.str_list(): - if 'autocfg' in i: - autocfg=True - break +smack_overrides(args) -if autocfg: - with open('/Users/marksb/src/smack/half-rs/newlog.txt', 'a') as f: - f.write('original: rustc ' + ' '.join(sys.argv[1:]) + '\n') - f.write('rewrite: rustc ' + ' '.join(args.str_list()) + '\n') - f.write('-'*80 + '\n') +argv = [] +for x in args['crate_types']: + argv.extend(['--crate-type', x]) +argv.append('--emit='+','.join(args['emit_types'])) +for a,v in args['codegen_opts'].items(): + argv.extend(['-C', a+'='+v if v else a]) +argv.extend(args['other_args']) - -proc = subprocess.run(['rustc'] + args.str_list(), env=os.environ) +with open('/Users/marksb/src/smack/half-rs/newlog.txt', 'a') as f: + f.write('original: rustc ' + ' '.join(sys.argv[1:]) + '\n') + f.write('rewrite: rustc ' + ' '.join(argv) + '\n') + f.write('-'*80 + '\n') + +#proc = subprocess.run(['rustc'] + args.str_list(), env=os.environ) #proc = subprocess.run(['rustc'] + sys.argv[1:], env=os.environ) +proc = subprocess.run(['rustc'] + argv, env=os.environ) exit(proc.returncode) From f0855a24725794525a715e41aab7034ca4bd750b Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 14:33:17 -0600 Subject: [PATCH 005/109] Switch to rustup --- bin/build.sh | 11 ++++------- bin/versions | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/bin/build.sh b/bin/build.sh index 215c4e8e9..b0f6b1a89 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -335,13 +335,10 @@ fi if [ ${INSTALL_RUST} -eq 1 ] ; then puts "Installing Rust" - ${WGET} https://static.rust-lang.org/dist/${RUST_VERSION}/rust-nightly-x86_64-unknown-linux-gnu.tar.gz -O rust.tar.gz - tar xf rust.tar.gz - cd rust-nightly-x86_64-unknown-linux-gnu - sudo ./install.sh --without=rust-docs - cd .. - rm -rf rust-nightly-x86_64-unknown-linux-gnu rust.tar.gz - cargo install rustfilt + if ! [ -x "$(command -v rustup)" ]; then + ${WGET} -O - --secure-protocol=TLSv1_2 https://sh.rustup.rs | bash -s -- -y + fi + rustup toolchain install ${RUST_VERSION} puts "Installed Rust" fi diff --git a/bin/versions b/bin/versions index a796e543a..79d87c422 100644 --- a/bin/versions +++ b/bin/versions @@ -7,4 +7,4 @@ SYMBOOGLIX_COMMIT=ccb2e7f2b3 LOCKPWN_COMMIT=12ba58f1ec LLVM_SHORT_VERSION=9 LLVM_FULL_VERSION=9.0.1 -RUST_VERSION=2020-05-21 +RUST_VERSION=nightly-2020-05-15 From a2d9827a92051c7674c2aac07d578c11508cf67b Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 15:04:55 -0600 Subject: [PATCH 006/109] Switch rustc to target toolchain --- share/smack/frontend.py | 2 ++ share/smack/versions.py | 1 + 2 files changed, 3 insertions(+) create mode 100644 share/smack/versions.py diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 35943bb02..792400c43 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -3,6 +3,7 @@ import re import json from .utils import temporary_file, try_command +from .versions import VERSIONS def languages(): @@ -268,6 +269,7 @@ def json_compilation_database_frontend(input_file, args): def default_rust_compile_command(args): compile_command = [ 'rustc', + '+'+VERSIONS['RUST_VERSION'], '-A', 'unused-imports', '-C', diff --git a/share/smack/versions.py b/share/smack/versions.py new file mode 100644 index 000000000..b5f751502 --- /dev/null +++ b/share/smack/versions.py @@ -0,0 +1 @@ +VERSIONS={'RUST_VERSION': 'nightly-2020-05-15'} From 6fe259d6cf13517d47e73537b0fea2ab21bf5f2a Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 15:08:16 -0600 Subject: [PATCH 007/109] Rustup support --- bin/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/build.sh b/bin/build.sh index b0f6b1a89..304776656 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -337,6 +337,7 @@ if [ ${INSTALL_RUST} -eq 1 ] ; then puts "Installing Rust" if ! [ -x "$(command -v rustup)" ]; then ${WGET} -O - --secure-protocol=TLSv1_2 https://sh.rustup.rs | bash -s -- -y + source $HOME/.cargo/env fi rustup toolchain install ${RUST_VERSION} puts "Installed Rust" From 8a89d0e69272a9fad48ea6bd3e90b6e0a4ea749a Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 15:21:07 -0600 Subject: [PATCH 008/109] Flake8 --- share/smack/smack-rustc.py | 178 ++++++++++++------------------------- 1 file changed, 56 insertions(+), 122 deletions(-) diff --git a/share/smack/smack-rustc.py b/share/smack/smack-rustc.py index 86f38eb89..7c34757ab 100755 --- a/share/smack/smack-rustc.py +++ b/share/smack/smack-rustc.py @@ -4,144 +4,78 @@ import os import subprocess -# $ rustc --help -v -# -# Usage: rustc [OPTIONS] INPUT -# -# Options: -# -h, --help Display this message -# --cfg SPEC Configure the compilation environment -# -L [KIND=]PATH Add a directory to the library search path. The -# optional KIND can be one of dependency, crate, native, -# framework, or all (the default). -# -l [KIND=]NAME Link the generated crate(s) to the specified native -# library NAME. The optional KIND can be one of -# static, framework, or dylib (the default). -# --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] -# Comma separated list of types of crates -# for the compiler to emit -# --crate-name NAME -# Specify the name of the crate being built -# --edition 2015|2018 -# Specify which edition of the compiler to use when -# compiling code. -# --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] -# Comma separated list of types of output for the -# compiler to emit -# --print [crate-name|file-names|sysroot|cfg|target-list|target-cpus|target-features|relocation-models|code-models|tls-models|target-spec-json|native-static-libs] -# Compiler information to print on stdout -# -g Equivalent to -C debuginfo=2 -# -O Equivalent to -C opt-level=2 -# -o FILENAME Write output to -# --out-dir DIR Write output to compiler-chosen filename in -# --explain OPT Provide a detailed explanation of an error message -# --test Build a test harness -# --target TARGET Target triple for which the code is compiled -# -W, --warn OPT Set lint warnings -# -A, --allow OPT Set lint allowed -# -D, --deny OPT Set lint denied -# -F, --forbid OPT Set lint forbidden -# --cap-lints LEVEL -# Set the most restrictive lint level. More restrictive -# lints are capped at this level -# -C, --codegen OPT[=VALUE] -# Set a codegen option -# -V, --version Print version info and exit -# -v, --verbose Use verbose output -# --extern NAME=PATH -# Specify where an external rust library is located -# --extern-private NAME=PATH -# Specify where an extern rust library is located, -# marking it as a private dependency -# --sysroot PATH Override the system root -# --error-format human|json|short -# How errors and other messages are produced -# --color auto|always|never -# Configure coloring of output: -# auto = colorize, if output goes to a tty (default); -# always = always colorize output; -# never = never colorize output -# --remap-path-prefix FROM=TO -# Remap source names in all output (compiler messages -# and output files) -# -# Additional help: -# -C help Print codegen options -# -W help Print 'lint' options and default settings -# -Z help Print unstable compiler options def smack_overrides(args): - args['codegen_opts'].update({'debuginfo': '2', - 'opt-level': '0', - 'no-prepopulate-passes': None, - 'passes':'name-anon-globals'}) + args['codegen_opts'].update({'debuginfo': '2', + 'opt-level': '0', + 'no-prepopulate-passes': None, + 'passes': 'name-anon-globals'}) def process_equals_arg(argv, i): - if '=' in argv[i]: - arg = argv[i].split('=')[-1] - else: - assert(len(argv) > i+1) - i += 1 - arg = argv[i] - return set(arg.split(',')), i - -def parse_args(argv = sys.argv): - crate_types = set() - emit_types = {'llvm-bc'} - other_args = [] - codegen_opts = dict() - i = 0 - while i < len(argv): - arg = argv[i] - # --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] - if False and arg.startswith('--crate-type'): - args, i = process_equals_arg(argv,i) - crate_types |= args - # --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] - elif arg.startswith('--emit'): - args, i = process_equals_arg(argv,i) - emit_types |= args - # codegen options -C opt, -C opt=opt -Copt - elif arg.startswith('-C'): - if arg == '-C': + if '=' in argv[i]: + arg = argv[i].split('=')[-1] + else: + assert(len(argv) > i+1) i += 1 arg = argv[i] - else: - arg = arg[2:] - - if len(arg.split('=')) == 2: - a, v = arg.split('=') - else: - a, v = arg, None - codegen_opts[a] = v - else: - other_args.append(argv[i]) - i += 1 - return {'crate_types': crate_types, - 'other_args' : other_args, - 'emit_types': emit_types, - 'codegen_opts': codegen_opts} - + return set(arg.split(',')), i + + +def parse_args(argv=sys.argv): + crate_types = set() + emit_types = {'llvm-bc'} + other_args = [] + codegen_opts = dict() + i = 0 + while i < len(argv): + arg = argv[i] + # --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] + if False and arg.startswith('--crate-type'): + args, i = process_equals_arg(argv, i) + crate_types |= args + # --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] + elif arg.startswith('--emit'): + args, i = process_equals_arg(argv, i) + emit_types |= args + # codegen options -C opt, -C opt=opt -Copt + elif arg.startswith('-C'): + if arg == '-C': + i += 1 + arg = argv[i] + else: + arg = arg[2:] + + if len(arg.split('=')) == 2: + a, v = arg.split('=') + else: + a, v = arg, None + codegen_opts[a] = v + else: + other_args.append(argv[i]) + i += 1 + return {'crate_types': crate_types, + 'other_args': other_args, + 'emit_types': emit_types, + 'codegen_opts': codegen_opts} + + args = parse_args(sys.argv[1:]) smack_overrides(args) argv = [] + for x in args['crate_types']: - argv.extend(['--crate-type', x]) + argv.extend(['--crate-type', x]) + argv.append('--emit='+','.join(args['emit_types'])) -for a,v in args['codegen_opts'].items(): - argv.extend(['-C', a+'='+v if v else a]) + +for a, v in args['codegen_opts'].items(): + argv.extend(['-C', a+'='+v if v else a]) + argv.extend(args['other_args']) -with open('/Users/marksb/src/smack/half-rs/newlog.txt', 'a') as f: - f.write('original: rustc ' + ' '.join(sys.argv[1:]) + '\n') - f.write('rewrite: rustc ' + ' '.join(argv) + '\n') - f.write('-'*80 + '\n') - -#proc = subprocess.run(['rustc'] + args.str_list(), env=os.environ) -#proc = subprocess.run(['rustc'] + sys.argv[1:], env=os.environ) proc = subprocess.run(['rustc'] + argv, env=os.environ) exit(proc.returncode) From 14f7125aa2e65a767c6997910dfa644f5deee61b Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 16:49:10 -0600 Subject: [PATCH 009/109] flake82 --- share/smack/versions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/smack/versions.py b/share/smack/versions.py index b5f751502..b75c64e5c 100644 --- a/share/smack/versions.py +++ b/share/smack/versions.py @@ -1 +1 @@ -VERSIONS={'RUST_VERSION': 'nightly-2020-05-15'} +VERSIONS = {'RUST_VERSION': 'nightly-2020-05-15'} From eff151d5d85b7dc47b857958ecaec153d1df38ec Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 17:46:35 -0600 Subject: [PATCH 010/109] Allow env in try_command --- {smack => share/smack/lib/smack}/.gitignore | 0 {smack => share/smack/lib/smack}/Cargo.toml | 0 {smack => share/smack/lib/smack}/build.rs | 0 {smack => share/smack/lib/smack}/src/lib.rs | 0 {smack => share/smack/lib/smack}/src/smack.c | 0 {smack => share/smack/lib/smack}/src/smack.h | 0 share/smack/utils.py | 5 ++++- 7 files changed, 4 insertions(+), 1 deletion(-) rename {smack => share/smack/lib/smack}/.gitignore (100%) rename {smack => share/smack/lib/smack}/Cargo.toml (100%) rename {smack => share/smack/lib/smack}/build.rs (100%) rename {smack => share/smack/lib/smack}/src/lib.rs (100%) rename {smack => share/smack/lib/smack}/src/smack.c (100%) rename {smack => share/smack/lib/smack}/src/smack.h (100%) diff --git a/smack/.gitignore b/share/smack/lib/smack/.gitignore similarity index 100% rename from smack/.gitignore rename to share/smack/lib/smack/.gitignore diff --git a/smack/Cargo.toml b/share/smack/lib/smack/Cargo.toml similarity index 100% rename from smack/Cargo.toml rename to share/smack/lib/smack/Cargo.toml diff --git a/smack/build.rs b/share/smack/lib/smack/build.rs similarity index 100% rename from smack/build.rs rename to share/smack/lib/smack/build.rs diff --git a/smack/src/lib.rs b/share/smack/lib/smack/src/lib.rs similarity index 100% rename from smack/src/lib.rs rename to share/smack/lib/smack/src/lib.rs diff --git a/smack/src/smack.c b/share/smack/lib/smack/src/smack.c similarity index 100% rename from smack/src/smack.c rename to share/smack/lib/smack/src/smack.c diff --git a/smack/src/smack.h b/share/smack/lib/smack/src/smack.h similarity index 100% rename from smack/src/smack.h rename to share/smack/lib/smack/src/smack.h diff --git a/share/smack/utils.py b/share/smack/utils.py index 2ba8e7978..3d1a3b091 100644 --- a/share/smack/utils.py +++ b/share/smack/utils.py @@ -29,13 +29,16 @@ def timeout_killer(proc, timed_out): os.killpg(os.getpgid(proc.pid), signal.SIGKILL) -def try_command(cmd, cwd=None, console=False, timeout=None): +def try_command(cmd, cwd=None, console=False, timeout=None, env=None): args = top.args console = (console or args.verbose or args.debug) and not args.quiet filelog = args.debug output = '' proc = None timer = None + if env is not None: + for k, v in env.items(): + os.putenv(k, v) try: if args.debug: print("Running %s" % " ".join(cmd)) From 29dc00d89004762c6aa13aa465a3cd857c434c86 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 22:10:08 -0600 Subject: [PATCH 011/109] Smack crate --- CMakeLists.txt | 2 +- share/smack/lib/smack/src/smack.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6ea010dc..8e8d723e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -203,5 +203,5 @@ INSTALL(FILES INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/share/smack DESTINATION share USE_SOURCE_PERMISSIONS - FILES_MATCHING PATTERN "*.py" PATTERN "*.h" PATTERN "*.c" PATTERN "Makefile" PATTERN "*.rs" PATTERN "*.f90" PATTERN "*.di" + FILES_MATCHING PATTERN "*.py" PATTERN "*.h" PATTERN "*.c" PATTERN "Makefile" PATTERN "*.rs" PATTERN "*.f90" PATTERN "*.di" PATTERN "*.toml" ) diff --git a/share/smack/lib/smack/src/smack.c b/share/smack/lib/smack/src/smack.c index c83d68d24..7b3bcf7df 100644 --- a/share/smack/lib/smack/src/smack.c +++ b/share/smack/lib/smack/src/smack.c @@ -103,9 +103,12 @@ unsigned short int __VERIFIER_nondet_unsigned_short_int(void) { } int __VERIFIER_nondet_int(void) { +#if !RUST_EXEC int x = __SMACK_nondet_int(); __VERIFIER_assume(x >= INT_MIN && x <= INT_MAX); return x; +#endif + return 0; } signed int __VERIFIER_nondet_signed_int(void) { @@ -124,12 +127,15 @@ unsigned __VERIFIER_nondet_unsigned(void) { } unsigned int __VERIFIER_nondet_unsigned_int(void) { +#if !RUST_EXEC unsigned int x = __SMACK_nondet_unsigned_int(); unsigned int min = __SMACK_nondet_unsigned_int(); unsigned int max = __SMACK_nondet_unsigned_int(); __VERIFIER_assume(min == 0 && max >= UINT_MAX && max <= UINT_MAX); __VERIFIER_assume(x >= min && x <= max); return x; +#endif + return 0; } long __VERIFIER_nondet_long(void) { From 6eb87c14f97bb71dedfcab0406c7e462a123032f Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 22:11:08 -0600 Subject: [PATCH 012/109] util support for crates --- share/smack/utils.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/share/smack/utils.py b/share/smack/utils.py index 3d1a3b091..fb16db72c 100644 --- a/share/smack/utils.py +++ b/share/smack/utils.py @@ -1,5 +1,6 @@ import os import sys +import shutil import tempfile import subprocess import signal @@ -17,10 +18,19 @@ def temporary_file(prefix, extension, args): return name +def temporary_directory(prefix, extension, args): + name = tempfile.mkdtemp(extension, prefix + '-', os.getcwd()) + if not args.debug: + temporary_files.append(name) + return name + + def remove_temp_files(): for f in temporary_files: if os.path.isfile(f): os.unlink(f) + elif os.path.isdir(f): + shutil.rmtree(f) def timeout_killer(proc, timed_out): From dd6e70b02625e4652cdd8dda80b30a206eaf49c2 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 22:14:52 -0600 Subject: [PATCH 013/109] Cargo frontend --- share/smack/frontend.py | 69 +++++++++++++++++++++++++++++++++++++- share/smack/smack-rustc.py | 14 ++------ 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 792400c43..301e033f9 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -2,7 +2,7 @@ import sys import re import json -from .utils import temporary_file, try_command +from .utils import temporary_file, try_command, temporary_directory from .versions import VERSIONS @@ -26,6 +26,7 @@ def languages(): 'f95': 'fortran', 'f03': 'fortran', 'rs': 'rust', + 'toml': 'cargo', } @@ -46,6 +47,7 @@ def frontends(): 'boogie': boogie_frontend, 'fortran': fortran_frontend, 'rust': rust_frontend, + 'cargo': cargo_frontend, } @@ -77,6 +79,10 @@ def smack_lib(): return os.path.join(smack_root(), 'share', 'smack', 'lib') +def smack_bin(): + return os.path.join(smack_root(), 'share', 'smack') + + def default_clang_compile_command(args, lib=False): cmd = ['clang', '-c', '-emit-llvm', '-O0', '-g', '-gcolumn-info'] # Starting from LLVM 5.0, we need the following two options @@ -266,6 +272,67 @@ def json_compilation_database_frontend(input_file, args): llvm_to_bpl(args) +def is_cargo_included_bc(name, args): + if not (len(name) > 3 and name[-3:] == '.bc'): + return False + + if name.startswith('smack-'): + # This is an artifact of the build process + return True + + if ',' in args.crates: + crates = set(args.crates.split(',')) + + else: + crates = args.crates + + for crate in crates: + if name.startswith(crate + '-'): + return True + + return False + + +def default_cargo_compile_command(args): + compile_command = [ + 'cargo', + '+'+VERSIONS['RUST_VERSION'], + 'build'] + return compile_command + args + + +def cargo_frontend(input_file, args): + """Generate LLVM bitcode from a cargo build.""" + targetdir = temporary_directory( + os.path.splitext( + os.path.basename(input_file))[0], + None, + args) + rustc = smack_bin() + '/smack-rustc.py' + compile_command = default_cargo_compile_command( + ['--target-dir', targetdir, '--manifest-path', input_file]) + try_command(compile_command, console=True, + env={'RUSTC': rustc}) + + # Get crate bc files + bcbase = targetdir+'/debug/deps/' + entries = os.listdir(bcbase) + print(entries) + bcs = [] + + for entry in entries: + if is_cargo_included_bc(entry, args): + bcs.append(bcbase + entry) + + bc_file = temporary_file( + os.path.splitext( + os.path.basename(input_file))[0], + '.bc', + args) + try_command(['llvm-link'] + bcs + ['-o', bc_file]) + return bc_file + + def default_rust_compile_command(args): compile_command = [ 'rustc', diff --git a/share/smack/smack-rustc.py b/share/smack/smack-rustc.py index 7c34757ab..a859c13c7 100755 --- a/share/smack/smack-rustc.py +++ b/share/smack/smack-rustc.py @@ -10,6 +10,7 @@ def smack_overrides(args): 'opt-level': '0', 'no-prepopulate-passes': None, 'passes': 'name-anon-globals'}) + args['other_args'].extend(['--cfg', 'verifier="smack"']) def process_equals_arg(argv, i): @@ -23,19 +24,14 @@ def process_equals_arg(argv, i): def parse_args(argv=sys.argv): - crate_types = set() emit_types = {'llvm-bc'} other_args = [] codegen_opts = dict() i = 0 while i < len(argv): arg = argv[i] - # --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] - if False and arg.startswith('--crate-type'): - args, i = process_equals_arg(argv, i) - crate_types |= args # --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] - elif arg.startswith('--emit'): + if arg.startswith('--emit'): args, i = process_equals_arg(argv, i) emit_types |= args # codegen options -C opt, -C opt=opt -Copt @@ -54,8 +50,7 @@ def parse_args(argv=sys.argv): else: other_args.append(argv[i]) i += 1 - return {'crate_types': crate_types, - 'other_args': other_args, + return {'other_args': other_args, 'emit_types': emit_types, 'codegen_opts': codegen_opts} @@ -66,9 +61,6 @@ def parse_args(argv=sys.argv): argv = [] -for x in args['crate_types']: - argv.extend(['--crate-type', x]) - argv.append('--emit='+','.join(args['emit_types'])) for a, v in args['codegen_opts'].items(): From 641bc28a2af5b43962dfd63301cf922d2e942548 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 22:16:50 -0600 Subject: [PATCH 014/109] Cargo example --- test/rust/cargo/cargo-test/Cargo.toml | 11 +++++++++++ test/rust/cargo/cargo-test/src/main.rs | 13 +++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 test/rust/cargo/cargo-test/Cargo.toml create mode 100644 test/rust/cargo/cargo-test/src/main.rs diff --git a/test/rust/cargo/cargo-test/Cargo.toml b/test/rust/cargo/cargo-test/Cargo.toml new file mode 100644 index 000000000..79063ada0 --- /dev/null +++ b/test/rust/cargo/cargo-test/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cargo-test" +version = "0.1.0" +authors = ["smackers"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +num-traits = "0.2.12" +smack = { path = "/usr/local/share/smack/lib/smack" } \ No newline at end of file diff --git a/test/rust/cargo/cargo-test/src/main.rs b/test/rust/cargo/cargo-test/src/main.rs new file mode 100644 index 000000000..57adf0d55 --- /dev/null +++ b/test/rust/cargo/cargo-test/src/main.rs @@ -0,0 +1,13 @@ +extern crate num_traits; +#[macro_use] +extern crate smack; +use smack::*; + +fn main() { + let a: u32 = 5.verifier_nondet(); + let b: u32 = 3.verifier_nondet(); + let c: u32 = 8.verifier_nondet(); + verifier_assume!(a <= c); + let d = num_traits::clamp(b, a, c); + verifier_assert!(a <= d && d <= c); +} From 31224bcfeaccd964a4aea29072ea4a2c6df74824 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 22:22:49 -0600 Subject: [PATCH 015/109] Convenience for crate spec --- share/smack/frontend.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 301e033f9..597bca57a 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -281,10 +281,13 @@ def is_cargo_included_bc(name, args): return True if ',' in args.crates: - crates = set(args.crates.split(',')) + crates = list(args.crates.split(',')) else: crates = args.crates + # Cargo replaces '-' in crate names with '_'. This is for + # convenience. + crates = set(map(lambda x: x.replace('-', '_'), crates)) for crate in crates: if name.startswith(crate + '-'): From af510903eece27c0823b9471c4b96fe0bf739b1d Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 22:44:07 -0600 Subject: [PATCH 016/109] Not upgrading Ubuntu --- bin/build.sh | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/bin/build.sh b/bin/build.sh index 304776656..57d594723 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -201,11 +201,6 @@ linux-@(ubuntu|neon)-18*) DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev" ;; -linux-@(ubuntu|neon)-20*) - Z3_DOWNLOAD_LINK="https://github.com/Z3Prover/z3/releases/download/z3-${Z3_VERSION}/z3-${Z3_VERSION}-x64-ubuntu-16.04.zip" - DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev" - ;; - *) puts "Distribution ${distro} not supported. Manual installation required." exit 1 @@ -242,7 +237,7 @@ if [ ${INSTALL_DEPENDENCIES} -eq 1 ] && [ "$TRAVIS" != "true" ] ; then sudo zypper --non-interactive install ${DEPENDENCIES} ;; - linux-@(ubuntu|neon)-@(1[68]|20)*) + linux-@(ubuntu|neon)-1[68]*) RELEASE_VERSION=$(get-platform-trim "$(lsb_release -r)" | awk -F: '{print $2;}') case "$RELEASE_VERSION" in 16*) @@ -251,9 +246,6 @@ if [ ${INSTALL_DEPENDENCIES} -eq 1 ] && [ "$TRAVIS" != "true" ] ; then 18*) UBUNTU_CODENAME="bionic" ;; - 20*) - UBUNTU_CODENAME="focal" - ;; *) puts "Release ${RELEASE_VERSION} for ${distro} not supported. Dependencies must be installed manually." exit 1 From 23b816d5d1a0ecbb073cd83d9c06612d12c27dd6 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 19 Aug 2020 22:45:15 -0600 Subject: [PATCH 017/109] Keep rustfilt --- bin/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/build.sh b/bin/build.sh index 57d594723..9d9b994e5 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -332,6 +332,7 @@ if [ ${INSTALL_RUST} -eq 1 ] ; then source $HOME/.cargo/env fi rustup toolchain install ${RUST_VERSION} + cargo install rustfilt puts "Installed Rust" fi From 976503e052b5ba78dec5895335f4ec03bb7faee5 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Fri, 21 Aug 2020 15:18:55 -0600 Subject: [PATCH 018/109] Crates option in top.py --- share/smack/top.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/share/smack/top.py b/share/smack/top.py index 49ddef237..e36fdce07 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -215,6 +215,12 @@ def arguments(): default='', help='additional compiler arguments (e.g., --clang-options="-w -g")') + frontend_group.add_argument( + '--crates', + default='*', + type=str, + help='Cargo crates to include in the analysis (comma separated)') + translate_group = parser.add_argument_group('translation options') translate_group.add_argument( From e80bc6c7ce65232540fdaad7c7e8e3f7dddc709c Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Fri, 21 Aug 2020 15:28:27 -0600 Subject: [PATCH 019/109] Remove print statement --- share/smack/frontend.py | 1 - 1 file changed, 1 deletion(-) diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 597bca57a..958ab23e6 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -320,7 +320,6 @@ def cargo_frontend(input_file, args): # Get crate bc files bcbase = targetdir+'/debug/deps/' entries = os.listdir(bcbase) - print(entries) bcs = [] for entry in entries: From 8f5b4d03845faa73bd5973d281725dcfc77a2561 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Mon, 31 Aug 2020 15:04:58 -0600 Subject: [PATCH 020/109] Fix --- share/smack/versions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/smack/versions.py b/share/smack/versions.py index b75c64e5c..ba8154688 100644 --- a/share/smack/versions.py +++ b/share/smack/versions.py @@ -1 +1 @@ -VERSIONS = {'RUST_VERSION': 'nightly-2020-05-15'} +VERSIONS = {'RUST_VERSION': 'nightly-2020-08-23'} From e0ee1c579ea06ec815747bde639b6b2ea1940fe4 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Mon, 31 Aug 2020 17:33:12 -0600 Subject: [PATCH 021/109] Add a pas to erase lang_start in Rust programs --- CMakeLists.txt | 2 ++ include/smack/RustFixes.h | 23 +++++++++++++ lib/smack/RustFixes.cpp | 59 ++++++++++++++++++++++++++++++++ lib/smack/SmackInstGenerator.cpp | 6 ---- tools/llvm2bpl/llvm2bpl.cpp | 2 ++ 5 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 include/smack/RustFixes.h create mode 100644 lib/smack/RustFixes.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e8d723e9..bfcd7f09e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,6 +131,7 @@ add_library(smackTranslator STATIC include/smack/VectorOperations.h include/smack/MemorySafetyChecker.h include/smack/IntegerOverflowChecker.h + include/smack/RustFixes.h include/smack/NormalizeLoops.h include/smack/SplitAggregateValue.h include/smack/Prelude.h @@ -155,6 +156,7 @@ add_library(smackTranslator STATIC lib/smack/VectorOperations.cpp lib/smack/MemorySafetyChecker.cpp lib/smack/IntegerOverflowChecker.cpp + lib/smack/RustFixes.cpp lib/smack/NormalizeLoops.cpp lib/smack/SplitAggregateValue.cpp lib/smack/Prelude.cpp diff --git a/include/smack/RustFixes.h b/include/smack/RustFixes.h new file mode 100644 index 000000000..887997839 --- /dev/null +++ b/include/smack/RustFixes.h @@ -0,0 +1,23 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// + +#ifndef RUSTFIXES_H +#define RUSTFIXES_H + +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" + +namespace smack { + +class RustFixes : public llvm::ModulePass { +public: + static char ID; // Pass identification, replacement for typeid + RustFixes() : llvm::ModulePass(ID) {} + virtual llvm::StringRef getPassName() const; + virtual bool runOnModule(llvm::Module &m); +}; +} // namespace smack + +#endif // RUSTFIXES_H diff --git a/lib/smack/RustFixes.cpp b/lib/smack/RustFixes.cpp new file mode 100644 index 000000000..a660099c5 --- /dev/null +++ b/lib/smack/RustFixes.cpp @@ -0,0 +1,59 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// + +#include "smack/RustFixes.h" +#include "smack/Naming.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include + +namespace smack { + +using namespace llvm; + +bool RustFixes::runOnModule(Module &m) { + std::vector instToErase; + for (auto &F : m) { + if (F.hasName() && Naming::isSmackName(F.getName())) + continue; + for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { + if (auto ci = dyn_cast(&*I)) { + if (Function *f = ci->getCalledFunction()) { + std::string name = f->hasName() ? f->getName() : ""; + if (name.find(Naming::RUST_ENTRY) != std::string::npos) { + // Get real Rust main + auto castExpr = ci->getArgOperand(0); + auto mainFunction = cast(castExpr); + auto callMain = CallInst::Create(mainFunction->getFunctionType(), + cast(mainFunction)); + + // Replace lang_start call... + auto retType = f->getReturnType(); + Constant *zero = ConstantInt::get(retType, 0); + auto *result = BinaryOperator::Create(Instruction::Add, zero, zero); + result->insertAfter(ci); + callMain->insertAfter(result); + I->replaceAllUsesWith(result); + + instToErase.push_back(&*I); + } + } + } + } + } + + for (auto I : instToErase) { + I->eraseFromParent(); + } + + return true; +} + +// Pass ID variable +char RustFixes::ID = 0; + +StringRef RustFixes::getPassName() const { return "Fixes for Rust programs"; } + +} // namespace smack diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index e3d147a55..16c002dd0 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -659,12 +659,6 @@ void SmackInstGenerator::visitCallInst(llvm::CallInst &ci) { ci.getType()->isVoidTy()); emit(Stmt::skip()); - } else if (name.find(Naming::RUST_ENTRY) != std::string::npos) { - // Set the entry point for Rust programs - auto castExpr = ci.getArgOperand(0); - auto mainFunction = cast(castExpr); - emit(Stmt::call(mainFunction->getName(), {}, {})); - } else if (SmackOptions::RustPanics && isRustPanic(name)) { // Convert Rust's panic functions into assertion violations emit(Stmt::assert_(Expr::lit(false), diff --git a/tools/llvm2bpl/llvm2bpl.cpp b/tools/llvm2bpl/llvm2bpl.cpp index 61427c5c9..18c869e39 100644 --- a/tools/llvm2bpl/llvm2bpl.cpp +++ b/tools/llvm2bpl/llvm2bpl.cpp @@ -35,6 +35,7 @@ #include "smack/MemorySafetyChecker.h" #include "smack/NormalizeLoops.h" #include "smack/RemoveDeadDefs.h" +#include "smack/RustFixes.h" #include "smack/SimplifyLibCalls.h" #include "smack/SmackModuleGenerator.h" #include "smack/SmackOptions.h" @@ -169,6 +170,7 @@ int main(int argc, char **argv) { } // pass_manager.add(new llvm::StructRet()); + pass_manager.add(new smack::RustFixes()); pass_manager.add(new smack::NormalizeLoops()); pass_manager.add(new llvm::SimplifyEV()); pass_manager.add(new llvm::SimplifyIV()); From 672981ccd5176ce6ed58ac3d03c3cbcecbdf1ed1 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Tue, 1 Sep 2020 00:10:13 -0600 Subject: [PATCH 022/109] No rustc wrapper --- share/smack/frontend.py | 33 ++++++++--------- share/smack/smack-rustc.py | 73 -------------------------------------- 2 files changed, 17 insertions(+), 89 deletions(-) delete mode 100755 share/smack/smack-rustc.py diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 958ab23e6..c6140e540 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -311,11 +311,12 @@ def cargo_frontend(input_file, args): os.path.basename(input_file))[0], None, args) - rustc = smack_bin() + '/smack-rustc.py' + rustargs = (default_rust_compile_args(args) + + ['--emit=llvm-bc', '-Clto', '-Cembed-bitcode=yes']) compile_command = default_cargo_compile_command( ['--target-dir', targetdir, '--manifest-path', input_file]) try_command(compile_command, console=True, - env={'RUSTC': rustc}) + env={'RUSTFLAGS': " ".join(rustargs)}) # Get crate bc files bcbase = targetdir+'/debug/deps/' @@ -334,22 +335,22 @@ def cargo_frontend(input_file, args): try_command(['llvm-link'] + bcs + ['-o', bc_file]) return bc_file +def default_rust_compile_args(args): + return ['-A', + 'unused-imports', + '-C', + 'opt-level=0', + '-C', + 'no-prepopulate-passes', + '-g', + '--cfg', + 'verifier="smack"', + '-C', + 'passes=name-anon-globals'] def default_rust_compile_command(args): - compile_command = [ - 'rustc', - '+'+VERSIONS['RUST_VERSION'], - '-A', - 'unused-imports', - '-C', - 'opt-level=0', - '-C', - 'no-prepopulate-passes', - '-g', - '--cfg', - 'verifier="smack"', - '-C', - 'passes=name-anon-globals'] + compile_command = (['rustc', '+'+VERSIONS['RUST_VERSION']] + + default_rust_compile_args(args)) return compile_command + args diff --git a/share/smack/smack-rustc.py b/share/smack/smack-rustc.py deleted file mode 100755 index a859c13c7..000000000 --- a/share/smack/smack-rustc.py +++ /dev/null @@ -1,73 +0,0 @@ -#! /usr/bin/env python3 - -import sys -import os -import subprocess - - -def smack_overrides(args): - args['codegen_opts'].update({'debuginfo': '2', - 'opt-level': '0', - 'no-prepopulate-passes': None, - 'passes': 'name-anon-globals'}) - args['other_args'].extend(['--cfg', 'verifier="smack"']) - - -def process_equals_arg(argv, i): - if '=' in argv[i]: - arg = argv[i].split('=')[-1] - else: - assert(len(argv) > i+1) - i += 1 - arg = argv[i] - return set(arg.split(',')), i - - -def parse_args(argv=sys.argv): - emit_types = {'llvm-bc'} - other_args = [] - codegen_opts = dict() - i = 0 - while i < len(argv): - arg = argv[i] - # --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] - if arg.startswith('--emit'): - args, i = process_equals_arg(argv, i) - emit_types |= args - # codegen options -C opt, -C opt=opt -Copt - elif arg.startswith('-C'): - if arg == '-C': - i += 1 - arg = argv[i] - else: - arg = arg[2:] - - if len(arg.split('=')) == 2: - a, v = arg.split('=') - else: - a, v = arg, None - codegen_opts[a] = v - else: - other_args.append(argv[i]) - i += 1 - return {'other_args': other_args, - 'emit_types': emit_types, - 'codegen_opts': codegen_opts} - - -args = parse_args(sys.argv[1:]) - -smack_overrides(args) - -argv = [] - -argv.append('--emit='+','.join(args['emit_types'])) - -for a, v in args['codegen_opts'].items(): - argv.extend(['-C', a+'='+v if v else a]) - -argv.extend(args['other_args']) - -proc = subprocess.run(['rustc'] + argv, env=os.environ) - -exit(proc.returncode) From a5f0a648ee16c74bd0cca1801b9b34bdbeb9aa32 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Thu, 17 Sep 2020 20:58:04 -0600 Subject: [PATCH 023/109] Rewrite rust simplification --- lib/smack/RustFixes.cpp | 110 +++++++++++++++++++++++++++--------- share/smack/frontend.py | 2 +- tools/llvm2bpl/llvm2bpl.cpp | 4 +- 3 files changed, 87 insertions(+), 29 deletions(-) diff --git a/lib/smack/RustFixes.cpp b/lib/smack/RustFixes.cpp index a660099c5..725318450 100644 --- a/lib/smack/RustFixes.cpp +++ b/lib/smack/RustFixes.cpp @@ -4,50 +4,106 @@ #include "smack/RustFixes.h" #include "smack/Naming.h" +#include "llvm/Analysis/CallGraph.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Module.h" +#include "llvm/Support/raw_ostream.h" #include +#include namespace smack { using namespace llvm; -bool RustFixes::runOnModule(Module &m) { +bool fixEntry(Function& main) { std::vector instToErase; - for (auto &F : m) { - if (F.hasName() && Naming::isSmackName(F.getName())) - continue; - for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { - if (auto ci = dyn_cast(&*I)) { - if (Function *f = ci->getCalledFunction()) { - std::string name = f->hasName() ? f->getName() : ""; - if (name.find(Naming::RUST_ENTRY) != std::string::npos) { - // Get real Rust main - auto castExpr = ci->getArgOperand(0); - auto mainFunction = cast(castExpr); - auto callMain = CallInst::Create(mainFunction->getFunctionType(), - cast(mainFunction)); - - // Replace lang_start call... - auto retType = f->getReturnType(); - Constant *zero = ConstantInt::get(retType, 0); - auto *result = BinaryOperator::Create(Instruction::Add, zero, zero); - result->insertAfter(ci); - callMain->insertAfter(result); - I->replaceAllUsesWith(result); - - instToErase.push_back(&*I); - } - } + bool isRustEntry = false; + for (inst_iterator I = inst_begin(main), E = inst_end(main); I != E; ++I) { + if (auto ci = dyn_cast(&*I)) { + if (Function *f = ci->getCalledFunction()) { + std::string name = f->hasName() ? f->getName() : ""; + if (name.find(Naming::RUST_ENTRY) != std::string::npos) { + isRustEntry = true; + // Get real Rust main + auto castExpr = ci->getArgOperand(0); + auto mainFunction = cast(castExpr); + auto callMain = CallInst::Create(mainFunction->getFunctionType(), + cast(mainFunction)); + + // Replace lang_start call... + auto retType = f->getReturnType(); + Constant *zero = ConstantInt::get(retType, 0); + auto *result = BinaryOperator::Create(Instruction::Add, zero, zero); + result->insertAfter(ci); + callMain->insertAfter(result); + I->replaceAllUsesWith(result); + + instToErase.push_back(&*I); + } } } } - + for (auto I : instToErase) { I->eraseFromParent(); } + return isRustEntry; +} + +void closeCalledFunctions(CallGraphNode *CGN, std::set &callees) { + if (!CGN) { return; } + + Function *function = CGN->getFunction(); + if (callees.count(function)) { return; } + callees.insert(CGN->getFunction()); + for (auto cr : *CGN) { + if (std::get<0>(cr)) { + closeCalledFunctions(std::get<1>(cr), callees); + } + } +} + +bool RustFixes::runOnModule(Module &m) { + std::set funcToErase; + std::set functions; + Function *mainFunction = nullptr; + bool isRust = false; + + for (auto &F : m) { + if (F.hasName()) { + auto name = F.getName(); + if (Naming::isSmackName(name)) + continue; + functions.insert(&F); + if (name == "main") { + isRust |= fixEntry(F); + mainFunction = &F; + } + else if (name.find("_ZN3std2rt19lang_start_internal") != std::string::npos || + name.find(Naming::RUST_ENTRY) != std::string::npos) { + funcToErase.insert(&F); + } + } + } + + for (auto F : funcToErase) { + F->dropAllReferences(); + } + + if (isRust) { + CallGraph CG = CallGraph(m); + auto mCFG = CG[mainFunction]; + std::set callees; + closeCalledFunctions(mCFG, callees); + + for (auto f : functions) { + if (!callees.count(f)) { + f->dropAllReferences(); + } + } + } return true; } diff --git a/share/smack/frontend.py b/share/smack/frontend.py index c6140e540..a88b39698 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -284,7 +284,7 @@ def is_cargo_included_bc(name, args): crates = list(args.crates.split(',')) else: - crates = args.crates + crates = [args.crates] # Cargo replaces '-' in crate names with '_'. This is for # convenience. crates = set(map(lambda x: x.replace('-', '_'), crates)) diff --git a/tools/llvm2bpl/llvm2bpl.cpp b/tools/llvm2bpl/llvm2bpl.cpp index 18c869e39..612257e37 100644 --- a/tools/llvm2bpl/llvm2bpl.cpp +++ b/tools/llvm2bpl/llvm2bpl.cpp @@ -155,6 +155,9 @@ int main(int argc, char **argv) { llvm::legacy::PassManager pass_manager; + pass_manager.add(new smack::RustFixes()); + pass_manager.add(llvm::createDeadCodeEliminationPass()); + pass_manager.add(llvm::createPrintModulePass(errs())); pass_manager.add(seadsa::createRemovePtrToIntPass()); pass_manager.add(llvm::createLowerSwitchPass()); // pass_manager.add(llvm::createCFGSimplificationPass()); @@ -170,7 +173,6 @@ int main(int argc, char **argv) { } // pass_manager.add(new llvm::StructRet()); - pass_manager.add(new smack::RustFixes()); pass_manager.add(new smack::NormalizeLoops()); pass_manager.add(new llvm::SimplifyEV()); pass_manager.add(new llvm::SimplifyIV()); From 4fe18e1c3c7e16eac75bee1c309858b00542bff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mark=20S=2E=20Baranowski=20=28Marek=20Stanis=C5=82aw=20Bar?= =?UTF-8?q?anowski=29?= Date: Wed, 23 Sep 2020 23:54:23 -0600 Subject: [PATCH 024/109] Add support for Ubuntu 20.04 Add Ubuntu 20.04 as a target in build.sh and update Vagrantfile. --- Vagrantfile | 2 +- bin/build.sh | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index bc66fc00b..67b33b4a7 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -10,7 +10,7 @@ Vagrant.configure(2) do |config| config.vm.synced_folder ".", "/home/vagrant/#{project_name}" config.vm.define :ubuntu do |ubuntu_config| - ubuntu_config.vm.box = "bento/ubuntu-18.04" + ubuntu_config.vm.box = "bento/ubuntu-20.04" end # This provision, 'fix-no-tty', gets rid of an error during build diff --git a/bin/build.sh b/bin/build.sh index 5751c9a3d..215c4e8e9 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -201,6 +201,11 @@ linux-@(ubuntu|neon)-18*) DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev" ;; +linux-@(ubuntu|neon)-20*) + Z3_DOWNLOAD_LINK="https://github.com/Z3Prover/z3/releases/download/z3-${Z3_VERSION}/z3-${Z3_VERSION}-x64-ubuntu-16.04.zip" + DEPENDENCIES+=" clang-${LLVM_SHORT_VERSION} llvm-${LLVM_SHORT_VERSION}-dev" + ;; + *) puts "Distribution ${distro} not supported. Manual installation required." exit 1 @@ -237,7 +242,7 @@ if [ ${INSTALL_DEPENDENCIES} -eq 1 ] && [ "$TRAVIS" != "true" ] ; then sudo zypper --non-interactive install ${DEPENDENCIES} ;; - linux-@(ubuntu|neon)-1[68]*) + linux-@(ubuntu|neon)-@(1[68]|20)*) RELEASE_VERSION=$(get-platform-trim "$(lsb_release -r)" | awk -F: '{print $2;}') case "$RELEASE_VERSION" in 16*) @@ -246,6 +251,9 @@ if [ ${INSTALL_DEPENDENCIES} -eq 1 ] && [ "$TRAVIS" != "true" ] ; then 18*) UBUNTU_CODENAME="bionic" ;; + 20*) + UBUNTU_CODENAME="focal" + ;; *) puts "Release ${RELEASE_VERSION} for ${distro} not supported. Dependencies must be installed manually." exit 1 From 7ce4ae8813d025ee544e7df6583bc680617c83fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mark=20S=2E=20Baranowski=20=28Marek=20Stanis=C5=82aw=20Bar?= =?UTF-8?q?anowski=29?= Date: Thu, 1 Oct 2020 10:56:52 -0600 Subject: [PATCH 025/109] Update Rust compiler installation to use rust-up Update Rust compiler installation to use rust-up - The Rust compiler version for SMACK is now installed as a toolchain - bin/versions is now installed as a Python module for access from frontend.py - Rust is no longer installed globally, and now installs in the preferred manner --- CMakeLists.txt | 6 ++++++ bin/build.sh | 11 +++++------ bin/versions | 20 ++++++++++---------- share/smack/frontend.py | 2 ++ 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6ea010dc..e9588f06a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,3 +205,9 @@ INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/share/smack USE_SOURCE_PERMISSIONS FILES_MATCHING PATTERN "*.py" PATTERN "*.h" PATTERN "*.c" PATTERN "Makefile" PATTERN "*.rs" PATTERN "*.f90" PATTERN "*.di" ) + +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/bin/versions + DESTINATION share/smack + RENAME versions.py +) diff --git a/bin/build.sh b/bin/build.sh index 215c4e8e9..c23329073 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -335,12 +335,11 @@ fi if [ ${INSTALL_RUST} -eq 1 ] ; then puts "Installing Rust" - ${WGET} https://static.rust-lang.org/dist/${RUST_VERSION}/rust-nightly-x86_64-unknown-linux-gnu.tar.gz -O rust.tar.gz - tar xf rust.tar.gz - cd rust-nightly-x86_64-unknown-linux-gnu - sudo ./install.sh --without=rust-docs - cd .. - rm -rf rust-nightly-x86_64-unknown-linux-gnu rust.tar.gz + if ! [ -x "$(command -v rustup)" ]; then + ${WGET} -O - --secure-protocol=TLSv1_2 https://sh.rustup.rs | bash -s -- -y + source $HOME/.cargo/env + fi + rustup toolchain install ${RUST_VERSION} cargo install rustfilt puts "Installed Rust" fi diff --git a/bin/versions b/bin/versions index c71e9e983..62cb1ad99 100644 --- a/bin/versions +++ b/bin/versions @@ -1,10 +1,10 @@ -Z3_VERSION=4.8.8 -CVC4_VERSION=1.8 -YICES2_VERSION=2.6.2 -BOOGIE_VERSION=2.7.15 -CORRAL_VERSION=1.0.12 -SYMBOOGLIX_COMMIT=ccb2e7f2b3 -LOCKPWN_COMMIT=12ba58f1ec -LLVM_SHORT_VERSION=10 -LLVM_FULL_VERSION=10.0.1 -RUST_VERSION=2020-08-23 +Z3_VERSION="4.8.8" +CVC4_VERSION="1.8" +YICES2_VERSION="2.6.2" +BOOGIE_VERSION="2.7.15" +CORRAL_VERSION="1.0.12" +SYMBOOGLIX_COMMIT="ccb2e7f2b3" +LOCKPWN_COMMIT="12ba58f1ec" +LLVM_SHORT_VERSION="10" +LLVM_FULL_VERSION="10.0.1" +RUST_VERSION="nightly-2020-08-23" diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 35943bb02..1479a9519 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -3,6 +3,7 @@ import re import json from .utils import temporary_file, try_command +from .versions import RUST_VERSION def languages(): @@ -268,6 +269,7 @@ def json_compilation_database_frontend(input_file, args): def default_rust_compile_command(args): compile_command = [ 'rustc', + '+' + RUST_VERSION, '-A', 'unused-imports', '-C', From e0243d4ea281b70c7e879e03444f1809840b2f30 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Thu, 1 Oct 2020 21:14:45 -0600 Subject: [PATCH 026/109] Update handling of Rust entry - Removes the call to lang_start in the main function at the IR level * This enables certain optimizations that are not available when rewriting at the bpl level - Remove lang_start functions from the IR * This allows dead code elimination to remove some globals that slow verification --- CMakeLists.txt | 2 + include/smack/Naming.h | 1 + include/smack/RustFixes.h | 23 ++++++++ lib/smack/Naming.cpp | 2 + lib/smack/RustFixes.cpp | 99 ++++++++++++++++++++++++++++++++ lib/smack/SmackInstGenerator.cpp | 6 -- tools/llvm2bpl/llvm2bpl.cpp | 5 ++ 7 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 include/smack/RustFixes.h create mode 100644 lib/smack/RustFixes.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e9588f06a..2de1a7369 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,6 +132,7 @@ add_library(smackTranslator STATIC include/smack/MemorySafetyChecker.h include/smack/IntegerOverflowChecker.h include/smack/NormalizeLoops.h + include/smack/RustFixes.h include/smack/SplitAggregateValue.h include/smack/Prelude.h include/smack/SmackWarnings.h @@ -156,6 +157,7 @@ add_library(smackTranslator STATIC lib/smack/MemorySafetyChecker.cpp lib/smack/IntegerOverflowChecker.cpp lib/smack/NormalizeLoops.cpp + lib/smack/RustFixes.cpp lib/smack/SplitAggregateValue.cpp lib/smack/Prelude.cpp lib/smack/SmackWarnings.cpp diff --git a/include/smack/Naming.h b/include/smack/Naming.h index 6e19318d3..e0abc112a 100644 --- a/include/smack/Naming.h +++ b/include/smack/Naming.h @@ -93,6 +93,7 @@ class Naming { static const std::string MEMORY_LEAK_FUNCTION; static const std::string RUST_ENTRY; + static const std::string RUST_LANG_START_INTERNAL; static const std::vector RUST_PANICS; static const std::string RUST_PANIC_ANNOTATION; diff --git a/include/smack/RustFixes.h b/include/smack/RustFixes.h new file mode 100644 index 000000000..887997839 --- /dev/null +++ b/include/smack/RustFixes.h @@ -0,0 +1,23 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// + +#ifndef RUSTFIXES_H +#define RUSTFIXES_H + +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" + +namespace smack { + +class RustFixes : public llvm::ModulePass { +public: + static char ID; // Pass identification, replacement for typeid + RustFixes() : llvm::ModulePass(ID) {} + virtual llvm::StringRef getPassName() const; + virtual bool runOnModule(llvm::Module &m); +}; +} // namespace smack + +#endif // RUSTFIXES_H diff --git a/lib/smack/Naming.cpp b/lib/smack/Naming.cpp index f4dd71358..ad6ba73e0 100644 --- a/lib/smack/Naming.cpp +++ b/lib/smack/Naming.cpp @@ -62,6 +62,8 @@ const std::string Naming::REC_MEM_OP = "boogie_si_record_mop"; const std::string Naming::MEM_OP_VAL = "$MOP"; const std::string Naming::RUST_ENTRY = "_ZN3std2rt10lang_start"; +const std::string Naming::RUST_LANG_START_INTERNAL = + "_ZN3std2rt19lang_start_internal"; const std::vector Naming::RUST_PANICS = { "_ZN3std9panicking15begin_panic_fmt17h", "_ZN4core9panicking5panic17h", "_ZN3std9panicking11begin_panic17h", "_ZN4core9panicking9panic_fmt17h", diff --git a/lib/smack/RustFixes.cpp b/lib/smack/RustFixes.cpp new file mode 100644 index 000000000..32c5809de --- /dev/null +++ b/lib/smack/RustFixes.cpp @@ -0,0 +1,99 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +// This patches Rust programs by removing certain language specific functions, +// enabling later optimizations. +// + +#include "smack/RustFixes.h" +#include "smack/Naming.h" +#include "llvm/Analysis/CallGraph.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +namespace smack { + +using namespace llvm; + +/* +The main function of rust programs looks like this: +... +%r = call i32 @std::rt::lang_start(..., @real_main, ...) +... + +This patches the main function to: +... +%r = 0 +call void @real_main(...) +... +*/ +void fixEntry(Function &main) { + std::vector instToErase; + + for (inst_iterator I = inst_begin(main), E = inst_end(main); I != E; ++I) { + if (auto ci = dyn_cast(&*I)) { + if (Function *f = ci->getCalledFunction()) { + std::string name = f->hasName() ? f->getName() : ""; + if (name.find(Naming::RUST_ENTRY) != std::string::npos) { + // Get real Rust main + auto castExpr = ci->getArgOperand(0); + auto mainFunction = cast(castExpr); + auto callMain = CallInst::Create(mainFunction->getFunctionType(), + cast(mainFunction)); + + // Replace the call to lang_start with the real Rust main function + auto retType = f->getReturnType(); + // Create a fake return value for this instruction + Constant *zero = ConstantInt::get(retType, 0); + auto *result = BinaryOperator::Create(Instruction::Add, zero, zero); + result->insertAfter(ci); + // Call the real main function + callMain->insertAfter(result); + I->replaceAllUsesWith(result); + + instToErase.push_back(&*I); + } + } + } + } + + for (auto I : instToErase) { + I->eraseFromParent(); + } +} + +bool RustFixes::runOnModule(Module &m) { + std::set funcToErase; + + for (auto &F : m) { + if (F.hasName()) { + auto name = F.getName(); + if (Naming::isSmackName(name)) + continue; + if (name == "main") { + fixEntry(F); + } else if (name.find(Naming::RUST_LANG_START_INTERNAL) != + std::string::npos || + name.find(Naming::RUST_ENTRY) != std::string::npos) { + funcToErase.insert(&F); + } + } + } + + for (auto F : funcToErase) { + F->dropAllReferences(); + } + + return true; +} + +// Pass ID variable +char RustFixes::ID = 0; + +StringRef RustFixes::getPassName() const { return "Fixes for Rust programs"; } + +} // namespace smack diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index e3d147a55..16c002dd0 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -659,12 +659,6 @@ void SmackInstGenerator::visitCallInst(llvm::CallInst &ci) { ci.getType()->isVoidTy()); emit(Stmt::skip()); - } else if (name.find(Naming::RUST_ENTRY) != std::string::npos) { - // Set the entry point for Rust programs - auto castExpr = ci.getArgOperand(0); - auto mainFunction = cast(castExpr); - emit(Stmt::call(mainFunction->getName(), {}, {})); - } else if (SmackOptions::RustPanics && isRustPanic(name)) { // Convert Rust's panic functions into assertion violations emit(Stmt::assert_(Expr::lit(false), diff --git a/tools/llvm2bpl/llvm2bpl.cpp b/tools/llvm2bpl/llvm2bpl.cpp index 61427c5c9..c659ead60 100644 --- a/tools/llvm2bpl/llvm2bpl.cpp +++ b/tools/llvm2bpl/llvm2bpl.cpp @@ -35,6 +35,7 @@ #include "smack/MemorySafetyChecker.h" #include "smack/NormalizeLoops.h" #include "smack/RemoveDeadDefs.h" +#include "smack/RustFixes.h" #include "smack/SimplifyLibCalls.h" #include "smack/SmackModuleGenerator.h" #include "smack/SmackOptions.h" @@ -154,6 +155,10 @@ int main(int argc, char **argv) { llvm::legacy::PassManager pass_manager; + // This runs before DSA because some Rust functions cause problems. + pass_manager.add(new smack::RustFixes); + pass_manager.add(llvm::createDeadCodeEliminationPass()); + pass_manager.add(seadsa::createRemovePtrToIntPass()); pass_manager.add(llvm::createLowerSwitchPass()); // pass_manager.add(llvm::createCFGSimplificationPass()); From e249ad8d5d7b2e18a61356514448fcff158bf21e Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sun, 11 Oct 2020 14:29:42 -0600 Subject: [PATCH 027/109] Added 33-bit integers into our list of supported integer widths Closes #622 --- lib/smack/Prelude.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/smack/Prelude.cpp b/lib/smack/Prelude.cpp index b72839886..ba20202ba 100644 --- a/lib/smack/Prelude.cpp +++ b/lib/smack/Prelude.cpp @@ -173,7 +173,7 @@ std::string getIntLimit(unsigned size) { } const std::vector IntOpGen::INTEGER_SIZES{ - 1, 5, 6, 8, 16, 24, 32, 40, 48, 56, 64, 80, 88, 96, 128, 160, 256}; + 1, 5, 6, 8, 16, 24, 32, 33, 40, 48, 56, 64, 80, 88, 96, 128, 160, 256}; // floating-point layout map: bit-width -> (exponent bit-width, significand // bit-width) From 945ec3476f6d98f4093fe0af92cc4e99a469397f Mon Sep 17 00:00:00 2001 From: Zvonimir Rakamaric Date: Mon, 12 Oct 2020 13:39:08 -0600 Subject: [PATCH 028/109] Updated Boogie, Corral, and Z3 I had to keep the old default Z3 arithmetic solver due to this issue: https://github.com/Z3Prover/z3/issues/4702 I am hoping that will get fixed in future releases. --- bin/versions | 8 ++++---- share/smack/svcomp/utils.py | 1 + share/smack/top.py | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/bin/versions b/bin/versions index 62cb1ad99..4bb97308d 100644 --- a/bin/versions +++ b/bin/versions @@ -1,10 +1,10 @@ -Z3_VERSION="4.8.8" +Z3_VERSION="4.8.9" CVC4_VERSION="1.8" YICES2_VERSION="2.6.2" -BOOGIE_VERSION="2.7.15" -CORRAL_VERSION="1.0.12" +BOOGIE_VERSION="2.7.30" +CORRAL_VERSION="1.0.14" SYMBOOGLIX_COMMIT="ccb2e7f2b3" LOCKPWN_COMMIT="12ba58f1ec" LLVM_SHORT_VERSION="10" LLVM_FULL_VERSION="10.0.1" -RUST_VERSION="nightly-2020-08-23" +RUST_VERSION="nightly-2020-08-23" \ No newline at end of file diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 2272df8e0..968533765 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -232,6 +232,7 @@ def verify_bpl_svcomp(args): corral_command += ["/tryCTrace", "/noTraceOnDisk", "/printDataValues:1"] corral_command += ["/useProverEvaluate", "/cex:1"] corral_command += ["/bopt:proverOpt:O:smt.qi.eager_threshold=100"] + corral_command += ["/bopt:proverOpt:O:smt.arith.solver=2"] with open(args.bpl_file, "r") as f: bpl = f.read() diff --git a/share/smack/top.py b/share/smack/top.py index 06343c8be..0edb65918 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -711,6 +711,7 @@ def verify_bpl(args): command += ["/errorLimit:%s" % args.max_violations] command += ["/proverOpt:O:smt.array.extensional=false"] command += ["/proverOpt:O:smt.qi.eager_threshold=100"] + command += ["/proverOpt:O:smt.arith.solver=2"] if not args.modular: command += ["/loopUnroll:%d" % args.unroll] if args.solver == 'cvc4': @@ -729,6 +730,7 @@ def verify_bpl(args): command += ["/maxStaticLoopBound:%d" % args.loop_limit] command += ["/recursionBound:%d" % args.unroll] command += ["/bopt:proverOpt:O:smt.qi.eager_threshold=100"] + command += ["/bopt:proverOpt:O:smt.arith.solver=2"] if args.solver == 'cvc4': command += ["/bopt:proverOpt:SOLVER=cvc4"] elif args.solver == 'yices2': From 0b0e6289bf3de09338721b214eeda638c6ddc375 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Tue, 13 Oct 2020 23:14:04 -0600 Subject: [PATCH 029/109] Use Python3's enumeration support to rewrite SMACK result handling --- share/smack/top.py | 110 ++++++++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 31 deletions(-) diff --git a/share/smack/top.py b/share/smack/top.py index 0edb65918..d043569e5 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -8,6 +8,7 @@ import subprocess import signal import functools +from enum import Flag, auto from .svcomp.utils import verify_bpl_svcomp from .utils import temporary_file, try_command, remove_temp_files from .replay import replay_error_trace @@ -16,22 +17,71 @@ VERSION = '2.6.0' -def results(args): - """A dictionary of the result output messages.""" - return { - 'verified': ('SMACK found no errors' - + ('' if args.modular else - ' with unroll bound %s' % args.unroll) + '.', 0), - 'error': ('SMACK found an error.', 1), - 'invalid-deref': ('SMACK found an error: invalid pointer dereference.', - 2), - 'invalid-free': ('SMACK found an error: invalid memory deallocation.', - 3), - 'invalid-memtrack': ('SMACK found an error: memory leak.', 4), - 'overflow': ('SMACK found an error: integer overflow.', 5), - 'rust-panic': ('SMACK found an error: Rust panic.', 6), - 'timeout': ('SMACK timed out.', 126), - 'unknown': ('SMACK result is unknown.', 127)} +class VResult(Flag): + VERIFIED = auto() + ASSERTION_FAILURE = auto() + INVALID_DEREF = auto() + INVALID_FREE = auto() + INVALID_MEMTRACK = auto() + OVERFLOW = auto() + RUST_PANIC = auto() + TIMEOUT = auto() + UNKNOWN = auto() + MEMSAFETY_ERROR = INVALID_DEREF | INVALID_FREE | INVALID_MEMTRACK + ERROR = (ASSERTION_FAILURE | INVALID_DEREF | INVALID_FREE + | INVALID_MEMTRACK | OVERFLOW | RUST_PANIC) + + def __str__(self): + return self.name.lower().replace('_', '-') + + def description(self): + descriptions = { + VResult.ASSERTION_FAILURE: '', + VResult.INVALID_DEREF: 'invalid pointer dereference', + VResult.INVALID_FREE: 'invalid memory deallocation', + VResult.INVALID_MEMTRACK: 'memory leak', + VResult.OVERFLOW: 'integer overflow', + VResult.RUST_PANIC: 'Rust panic'} + + if self in descriptions: + return descriptions[self] + else: + raise RuntimeError('No description associated with result: %s' + % self) + + def return_code(self): + return_codes = { + VResult.VERIFIED: 0, + VResult.ASSERTION_FAILURE: 1, + VResult.INVALID_DEREF: 2, + VResult.INVALID_FREE: 3, + VResult.INVALID_MEMTRACK: 4, + VResult.OVERFLOW: 5, + VResult.RUST_PANIC: 6, + VResult.TIMEOUT: 126, + VResult.UNKNOWN: 127} + + if self in return_codes: + return return_codes[self] + else: + raise RuntimeError('No return code associated with result: %s' + % self) + + def message(self, args): + if self is VResult.VERIFIED: + return ('SMACK found no errors' + + ('' if args.modular else ' with unroll bound %s' + % args.unroll) + '.') + elif self in VResult.ERROR: + description = self.description() + return ('SMACK found an error' + + (': %s' % description if description else '') + '.') + elif self is VResult.TIMEOUT: + return 'SMACK timed out.' + elif self is VResult.UNKNOWN: + return 'SMACK result is unknown.' + else: + raise RuntimeError('No message associated with result: %s' % self) def inlined_procedures(): @@ -663,36 +713,36 @@ def verification_result(verifier_output): if re.search( r'[1-9]\d* time out|Z3 ran out of resources|timed out|ERRORS_TIMEOUT', verifier_output): - return 'timeout' + return VResult.TIMEOUT elif re.search((r'[1-9]\d* verified, 0 errors?|no bugs|' r'NO_ERRORS_NO_TIMEOUT'), verifier_output): - return 'verified' + return VResult.VERIFIED elif re.search((r'\d* verified, [1-9]\d* errors?|can fail|' r'ERRORS_NO_TIMEOUT'), verifier_output): if re.search( r'ASSERTION FAILS assert {:valid_deref}', verifier_output): - return 'invalid-deref' + return VResult.INVALID_DEREF elif re.search(r'ASSERTION FAILS assert {:valid_free}', verifier_output): - return 'invalid-free' + return VResult.INVALID_FREE elif re.search(r'ASSERTION FAILS assert {:valid_memtrack}', verifier_output): - return 'invalid-memtrack' + return VResult.INVALID_MEMTRACK elif re.search(r'ASSERTION FAILS assert {:overflow}', verifier_output): - return 'overflow' + return VResult.OVERFLOW elif re.search(r'ASSERTION FAILS assert {:rust_panic}', verifier_output): - return 'rust-panic' + return VResult.RUST_PANIC else: listCall = re.findall(r'\(CALL .+\)', verifier_output) if len(listCall) > 0 and re.search( r'free_', listCall[len(listCall) - 1]): - return 'invalid-free' + return VResult.INVALID_FREE else: - return 'error' + return VResult.ASSERTION_FAILURE else: - return 'unknown' + return VResult.UNKNOWN def verify_bpl(args): @@ -754,9 +804,7 @@ def verify_bpl(args): if args.smackd: print(smackdOutput(verifier_output)) else: - if (result == 'error' or result == 'invalid-deref' or - result == 'invalid-free' or result == 'invalid-memtrack' or - result == 'overflow' or result == 'rust-panic'): + if result in VResult.ERROR: error = error_trace(verifier_output, args) if args.error_file: @@ -768,8 +816,8 @@ def verify_bpl(args): if args.replay: replay_error_trace(verifier_output, args) - print(results(args)[result][0]) - sys.exit(results(args)[result][1]) + print(result.message(args)) + sys.exit(result.return_code()) def error_step(step): From 36d86b7521113c0771a5adc2ea05bf0103dbd63e Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Wed, 14 Oct 2020 18:46:58 -0600 Subject: [PATCH 030/109] Used Python's enum support to rewrite check option. --- share/smack/frontend.py | 8 ++- share/smack/top.py | 128 +++++++++++++++++++++++++++++----------- 2 files changed, 98 insertions(+), 38 deletions(-) diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 1479a9519..dc933a727 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -86,10 +86,12 @@ def default_clang_compile_command(args, lib=False): cmd += ['-I' + path for path in smack_headers(args)] cmd += args.clang_options.split() cmd += ['-DMEMORY_MODEL_' + args.mem_mod.upper().replace('-', '_')] - if ('memory-safety' in args.check or 'valid-deref' in args.check or - 'valid-free' in args.check or 'memleak' in args.check): + + from .top import VProperty + + if args.check.contains_mem_safe_props(): cmd += ['-DMEMORY_SAFETY'] - if 'integer-overflow' in args.check: + if VProperty.INTEGER_OVERFLOW in args.check: cmd += (['-fsanitize=signed-integer-overflow,shift'] if not lib else ['-DSIGNED_INTEGER_OVERFLOW_CHECK']) if args.float: diff --git a/share/smack/top.py b/share/smack/top.py index d043569e5..8392679f5 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -84,6 +84,78 @@ def message(self, args): raise RuntimeError('No message associated with result: %s' % self) +class PropertyAction(argparse.Action): + def __init__(self, option_strings, dest, **kwargs): + super(PropertyAction, self).__init__(option_strings, dest, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + setattr(namespace, self.dest, + functools.reduce(lambda x, y: x | y, values, + getattr(namespace, self.dest))) + + +# Shaobo: shamelessly borrowed it from https://stackoverflow.com/a/55500795 +class VProperty(Flag): + ASSERTIONS = auto() + VALID_DEREF = auto() + VALID_FREE = auto() + MEMLEAK = auto() + MEMORY_SAFETY = VALID_DEREF | VALID_FREE | MEMLEAK + INTEGER_OVERFLOW = auto() + RUST_PANIC = auto() + + def __str__(self): + return self.name.lower().replace('_', '-') + + def __repr__(self): + return str(self) + + @staticmethod + def argparse(s): + try: + return VProperty[s.upper().replace('-', '_')] + except KeyError: + return s + + @staticmethod + def mem_safe_subprops(): + return [VProperty.VALID_DEREF, VProperty.VALID_FREE, VProperty.MEMLEAK] + + def contains_mem_safe_props(self): + return bool(self & VProperty.MEMORY_SAFETY) + + def boogie_attr(self): + def lower_name(x): + return x.name.lower() + + attrs = { + VProperty.VALID_DEREF: lower_name(VProperty.VALID_DEREF), + VProperty.VALID_FREE: lower_name(VProperty.VALID_FREE), + VProperty.MEMLEAK: 'valid_memtrack', + VProperty.INTEGER_OVERFLOW: 'overflow', + VProperty.RUST_PANIC: lower_name(VProperty.RUST_PANIC)} + + if self in attrs: + return attrs[self] + else: + raise RuntimeError('No assertion Boogie attribute associated with' + 'property: %s' % self) + + def result(self): + res = { + VProperty.VALID_DEREF: VResult.INVALID_DEREF, + VProperty.VALID_FREE: VResult.INVALID_FREE, + VProperty.MEMLEAK: VResult.INVALID_MEMTRACK, + VProperty.INTEGER_OVERFLOW: VResult.OVERFLOW, + VProperty.RUST_PANIC: VResult.RUST_PANIC} + + if self in res: + return res[self] + else: + raise RuntimeError(('No SMACK result associated with property: %s' + % self)) + + def inlined_procedures(): return [ '$galloc', @@ -353,9 +425,10 @@ def arguments(): '--check', metavar='PROPERTY', nargs='+', - choices=['assertions', 'memory-safety', 'valid-deref', 'valid-free', - 'memleak', 'integer-overflow', 'rust-panics'], - default=['assertions'], + choices=list(VProperty), + default=VProperty.ASSERTIONS, + type=VProperty.argparse, + action=PropertyAction, help='''select properties to check [choices: %(choices)s; default: %(default)s] (note that memory-safety is the union of valid-deref, @@ -600,12 +673,11 @@ def llvm_to_bpl(args): cmd += ['-no-byte-access-inference'] if args.no_memory_splitting: cmd += ['-no-memory-splitting'] - if ('memory-safety' in args.check or 'valid-deref' in args.check or - 'valid-free' in args.check or 'memleak' in args.check): + if args.check.contains_mem_safe_props(): cmd += ['-memory-safety'] - if 'integer-overflow' in args.check: + if VProperty.INTEGER_OVERFLOW in args.check: cmd += ['-integer-overflow'] - if 'rust-panics' in args.check: + if VProperty.RUST_PANIC in args.check: cmd += ['-rust-panics'] if args.llvm_assumes: cmd += ['-llvm-assumes=' + args.llvm_assumes] @@ -650,15 +722,11 @@ def annotate_bpl(args): def memsafety_subproperty_selection(args): - selected_props = set() - if 'memory-safety' in args.check: + if VProperty.MEMORY_SAFETY in args.check: return - if 'valid-deref' in args.check: - selected_props.add('valid_deref') - if 'valid-free' in args.check: - selected_props.add('valid_free') - if 'memleak' in args.check: - selected_props.add('valid_memtrack') + + selected_props = [p.boogie_attr() for p in VProperty.mem_safe_subprops() + if p in args.check] def replace_assertion(m): if len(selected_props) > 0: @@ -719,28 +787,18 @@ def verification_result(verifier_output): return VResult.VERIFIED elif re.search((r'\d* verified, [1-9]\d* errors?|can fail|' r'ERRORS_NO_TIMEOUT'), verifier_output): - if re.search( - r'ASSERTION FAILS assert {:valid_deref}', - verifier_output): - return VResult.INVALID_DEREF - elif re.search(r'ASSERTION FAILS assert {:valid_free}', - verifier_output): + for p in (VProperty.mem_safe_subprops() + [VProperty.INTEGER_OVERFLOW] + + [VProperty.RUST_PANIC]): + if re.search(r'ASSERTION FAILS assert {:%s}' % p.boogie_attr(), + verifier_output): + return p.result() + + listCall = re.findall(r'\(CALL .+\)', verifier_output) + if len(listCall) > 0 and re.search( + r'free_', listCall[len(listCall) - 1]): return VResult.INVALID_FREE - elif re.search(r'ASSERTION FAILS assert {:valid_memtrack}', - verifier_output): - return VResult.INVALID_MEMTRACK - elif re.search(r'ASSERTION FAILS assert {:overflow}', verifier_output): - return VResult.OVERFLOW - elif re.search(r'ASSERTION FAILS assert {:rust_panic}', - verifier_output): - return VResult.RUST_PANIC else: - listCall = re.findall(r'\(CALL .+\)', verifier_output) - if len(listCall) > 0 and re.search( - r'free_', listCall[len(listCall) - 1]): - return VResult.INVALID_FREE - else: - return VResult.ASSERTION_FAILURE + return VResult.ASSERTION_FAILURE else: return VResult.UNKNOWN From 59821c198b9d98fc12c67f2139733e038767c7ad Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Wed, 14 Oct 2020 21:13:52 -0600 Subject: [PATCH 031/109] Minor fix --- share/smack/top.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/share/smack/top.py b/share/smack/top.py index 8392679f5..c9bd0eaa6 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -102,7 +102,7 @@ class VProperty(Flag): MEMLEAK = auto() MEMORY_SAFETY = VALID_DEREF | VALID_FREE | MEMLEAK INTEGER_OVERFLOW = auto() - RUST_PANIC = auto() + RUST_PANICS = auto() def __str__(self): return self.name.lower().replace('_', '-') @@ -125,15 +125,18 @@ def contains_mem_safe_props(self): return bool(self & VProperty.MEMORY_SAFETY) def boogie_attr(self): - def lower_name(x): - return x.name.lower() + def get_attr_from_result(x): + if x in VProperty.mem_safe_subprops(): + return x.name.lower()[2:] + else: + return x.name.lower() attrs = { - VProperty.VALID_DEREF: lower_name(VProperty.VALID_DEREF), - VProperty.VALID_FREE: lower_name(VProperty.VALID_FREE), - VProperty.MEMLEAK: 'valid_memtrack', - VProperty.INTEGER_OVERFLOW: 'overflow', - VProperty.RUST_PANIC: lower_name(VProperty.RUST_PANIC)} + VProperty.VALID_DEREF: get_attr_from_result(VResult.INVALID_DEREF), + VProperty.VALID_FREE: get_attr_from_result(VResult.INVALID_FREE), + VProperty.MEMLEAK: get_attr_from_result(VResult.INVALID_MEMTRACK), + VProperty.INTEGER_OVERFLOW: get_attr_from_result(VResult.OVERFLOW), + VProperty.RUST_PANICS: get_attr_from_result(VResult.RUST_PANIC)} if self in attrs: return attrs[self] @@ -147,7 +150,7 @@ def result(self): VProperty.VALID_FREE: VResult.INVALID_FREE, VProperty.MEMLEAK: VResult.INVALID_MEMTRACK, VProperty.INTEGER_OVERFLOW: VResult.OVERFLOW, - VProperty.RUST_PANIC: VResult.RUST_PANIC} + VProperty.RUST_PANICS: VResult.RUST_PANIC} if self in res: return res[self] @@ -677,7 +680,7 @@ def llvm_to_bpl(args): cmd += ['-memory-safety'] if VProperty.INTEGER_OVERFLOW in args.check: cmd += ['-integer-overflow'] - if VProperty.RUST_PANIC in args.check: + if VProperty.RUST_PANICS in args.check: cmd += ['-rust-panics'] if args.llvm_assumes: cmd += ['-llvm-assumes=' + args.llvm_assumes] @@ -788,7 +791,7 @@ def verification_result(verifier_output): elif re.search((r'\d* verified, [1-9]\d* errors?|can fail|' r'ERRORS_NO_TIMEOUT'), verifier_output): for p in (VProperty.mem_safe_subprops() + [VProperty.INTEGER_OVERFLOW] - + [VProperty.RUST_PANIC]): + + [VProperty.RUST_PANICS]): if re.search(r'ASSERTION FAILS assert {:%s}' % p.boogie_attr(), verifier_output): return p.result() From 3b01ea54a933dde2a5e9c85857aea79cda83eed1 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Thu, 15 Oct 2020 18:05:43 -0600 Subject: [PATCH 032/109] Cleaned up SVCOMP heuristics --- share/smack/svcomp/utils.py | 155 +----------------------------------- 1 file changed, 2 insertions(+), 153 deletions(-) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 968533765..45d2904f7 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -90,43 +90,6 @@ def svcomp_process_file(args, name, ext): with open(args.input_files[0], 'r') as fi: s = fi.read() args.input_files[0] = smack.top.temporary_file(name, ext, args) - # replace exit definition with exit_ - s = re.sub(r'void\s+exit\s*\(int s\)', r'void exit_(int s)', s) - if not ('direc_start' in s or 'just_echo' in s): - s = re.sub(r'argv\[i\]=malloc\(11\);\s+argv\[i\]\[10\]\s+=\s+0;\s+for\(int\s+j=0;\s+j<10;\s+\+\+j\)\s+argv\[i\]\[j\]=__VERIFIER_nondet_char\(\);', r'argv[i] = malloc(3);\n argv[i][0] = __VERIFIER_nondet_char();\n argv[i][1] = __VERIFIER_nondet_char();\n argv[i][2] = 0;', s) - s = re.sub(r'char\s+\*a\s+=\s+malloc\(11\);\s+a\[10\]\s+=\s+0;\s+for\(int\s+i=0;\s+i<10;\s+\+\+i\)\s+a\[i\]=__VERIFIER_nondet_char\(\);', r'char *a = malloc(3);\n a[0] = __VERIFIER_nondet_char();\n a[1] = __VERIFIER_nondet_char();\n a[2] = 0;', s) - s = re.sub(r'static\s+char\s+dir\[42\];\s+for\(int\s+i=0;\s+i<42;\s+\+\+i\)\s+dir\[i\]\s+=\s+__VERIFIER_nondet_char\(\);\s+dir\[41\]\s+=\s+\'\\0\';', r'static char dir[3];\n dir[0] = __VERIFIER_nondet_char();\n dir[1] = __VERIFIER_nondet_char();\n dir[2] = 0;', s) - s = re.sub(r'__VERIFIER_assume\(i < 16\);', r'__VERIFIER_assume(i >= 0 && i < 16);', s) - - if 'memory-safety' in args.check and not 'argv=malloc' in s: - s = re.sub(r'typedef long unsigned int size_t', r'typedef unsigned int size_t', s) - elif 'memory-safety' in args.check and re.search(r'getopt32\([^,)]+,[^,)]+,[^.)]+\);', s): - if not args.quiet: - print("Stumbled upon a benchmark that requires precise handling of vararg\n") - while (True): - pass - elif 'memory-safety' in args.check and ('count is too big' in s or 'pdRfilsLHarPv' in s or 'rnugG' in s): - if not args.quiet: - print("Stumbled upon a benchmark that contains undefined behavior\n") - while (True): - pass - - if 'argv=malloc' in s: -# args.integer_encoding = 'bit-vector' - if 'integer-overflow' in args.check and ('unsigned int d = (unsigned int)((signed int)(unsigned char)((signed int)*q | (signed int)(char)32) - 48);' in s or 'bb_ascii_isalnum' in s or 'ptm=localtime' in s or '0123456789.' in s): - args.integer_encoding = 'bit-vector' - args.pointer_encoding = 'bit-vector' - - length = len(s.split('\n')) - if length < 60: - # replace all occurrences of 100000 with 10 and 15000 with 5 - # Only target at small examples - s = re.sub(r'100000', r'10', s) - s = re.sub(r'15000', r'5', s) - s = re.sub(r'i<=10000', r'i<=1', s) - s = re.sub(r'500000', r'50', s) - elif length < 710 and 'dll_create_master' in s: - args.no_memory_splitting = True #Remove any preprocessed declarations of pthread types #Also, if file contains 'pthread', set pthread mode @@ -140,36 +103,6 @@ def force_timeout(): sys.stdout.flush() time.sleep(1000) -def is_buggy_driver_benchmark(args, bpl): - if ("205_9a_array_safes_linux-3.16-rc1.tar.xz-205_9a-drivers--net--usb--rtl8150.ko-entry_point_true-unreach-call" in bpl or - "32_7a_cilled_true-unreach-call_linux-3.8-rc1-32_7a-drivers--gpu--drm--ttm--ttm.ko-ldv_main5_sequence_infinite_withcheck_stateful" in bpl or - "32_7a_cilled_true-unreach-call_linux-3.8-rc1-32_7a-drivers--media--dvb-core--dvb-core.ko-ldv_main5_sequence_infinite_withcheck_stateful" in bpl or - "32_7a_cilled_true-unreach-call_linux-3.8-rc1-32_7a-sound--core--seq--snd-seq.ko-ldv_main2_sequence_infinite_withcheck_stateful" in bpl or - "43_2a_bitvector_linux-3.16-rc1.tar.xz-43_2a-drivers--net--xen-netfront.ko-entry_point_true-unreach-call" in bpl or - "linux-3.14__complex_emg__linux-drivers-clk1__drivers-net-ethernet-ethoc_true-unreach-call" in bpl or - "linux-3.14__linux-usb-dev__drivers-media-usb-hdpvr-hdpvr_true-unreach-call" in bpl or - "linux-4.2-rc1.tar.xz-32_7a-drivers--net--usb--r8152.ko-entry_point_true-unreach-call" in bpl or - "linux-3.14__complex_emg__linux-kernel-locking-spinlock__drivers-net-ethernet-smsc-smsc911x_true-unreach-call" in bpl or - "linux-3.14__complex_emg__linux-kernel-locking-spinlock__drivers-net-wan-lmc-lmc_true-unreach-call" in bpl or - "linux-4.2-rc1.tar.xz-32_7a-drivers--usb--gadget--libcomposite.ko-entry_point_true-unreach-call" in bpl or - "linux-3.14__complex_emg__linux-kernel-locking-spinlock__drivers-media-platform-marvell-ccic-cafe_ccic_true-unreach-call" in bpl or - "linux-4.0-rc1---drivers--media--usb--uvc--uvcvideo.ko_false-unreach-call" in bpl or - "linux-4.0-rc1---drivers--char--ipmi--ipmi_msghandler.ko_true-unreach-call" in bpl or - "205_9a_array_safes_linux-3.16-rc1.tar.xz-205_9a-drivers--net--wireless--libertas_tf--libertas_tf.ko-entry_point_true-unreach-call" in bpl or - "linux-4.2-rc1.tar.xz-32_7a-drivers--md--dm-raid.ko-entry_point_false-unreach-call" in bpl or - "linux-4.2-rc1.tar.xz-43_2a-drivers--net--ppp--ppp_generic.ko-entry_point_true-unreach-call" in bpl): - if not args.quiet: - print("Stumbled upon a buggy device driver benchmark\n") - force_timeout() - -def is_stack_benchmark(args, csource): - if ("getNumbers" in csource or "areNatural" in csource or "myPointerA" in csource or "if(i == 0) {" in csource or - "arr[194]" in csource or "if(1)" in csource or "alloca(10" in csource or "p[0] = 2;" in csource): - if not args.quiet: - print("Stumbled upon a stack-based memory safety benchmark\n") - print(smack.top.results(args)['unknown'][0]) - sys.exit(smack.top.results(args)['unknown'][1]) - def inject_assert_false(args): with open(args.bpl_file, 'r') as bf: content = bf.read() @@ -240,21 +173,6 @@ def verify_bpl_svcomp(args): with open(args.input_files[0], "r") as f: csource = f.read() - if 'memory-safety' in args.check: - is_stack_benchmark(args, csource) - else: - if "angleInRadian" in csource: - if not args.quiet: - print("Stumbled upon trigonometric function is float benchmark\n") - print(smack.top.results(args)['unknown'][0]) - sys.exit(smack.top.results(args)['unknown'][1]) - elif "copysign(1" in csource: - if not args.quiet: - print("Stumbled upon tricky float benchmark\n") - print(smack.top.results(args)['unknown'][0]) - sys.exit(smack.top.results(args)['unknown'][1]) - is_buggy_driver_benchmark(args, bpl) - if args.pthread: if "fib_bench" in bpl or "27_Boop_simple_vf_false-unreach-call" in bpl or "k < 5;" in csource or "k < 10;" in csource or "k < 20;" in csource: heurTrace += "Increasing context switch bound for certain pthread benchmarks.\n" @@ -269,78 +187,9 @@ def verify_bpl_svcomp(args): if not ("dll_create" in csource or "sll_create" in csource or "changeMethaneLevel" in csource): corral_command += ["/di"] - # we are not modeling strcpy - if args.pthread and "strcpy" in bpl: - heurTrace += "We are not modeling strcpy - aborting\n" - if not args.quiet: - print((heurTrace + "\n")) - print(smack.top.results(args)['unknown'][0]) - sys.exit(smack.top.results(args)['unknown'][1]) - # Setting good loop unroll bound based on benchmark class - loopUnrollBar = 8 - staticLoopBound = 65536 - if not args.integer_encoding == 'bit-vector' and "ssl3_accept" in bpl and "s__s3__tmp__new_cipher__algorithms" in bpl: - heurTrace += "ControlFlow benchmark detected. Setting loop unroll bar to 23.\n" - loopUnrollBar = 23 - elif "s3_srvr.blast.10_false-unreach-call" in bpl or "s3_srvr.blast.15_false-unreach-call" in bpl: - heurTrace += "ControlFlow benchmark detected. Setting loop unroll bar to 23.\n" - loopUnrollBar = 23 - elif "NonTerminationSimple4_false-no-overflow" in bpl: - heurTrace += "Overflow benchmark detected. Setting loop unroll bar to 1024.\n" - loopUnrollBar = 1024 - elif " node3" in bpl: - heurTrace += "Sequentialized benchmark detected. Setting loop unroll bar to 100.\n" - loopUnrollBar = 100 - elif "calculate_output" in bpl or "psyco" in bpl: - heurTrace += "ECA benchmark detected. Setting loop unroll bar to 15.\n" - loopUnrollBar = 15 - elif "ldv" in bpl: - if "linux-4.2-rc1.tar.xz-08_1a-drivers--staging--lustre--lustre--llite--llite_lloop.ko-entry_point" in bpl or "linux-3.14__complex_emg__linux-usb-dev__drivers-media-usb-hdpvr-hdpvr" in bpl: - heurTrace += "Special LDV benchmark detected. Setting loop unroll bar to 32.\n" - loopUnrollBar = 32 - else: - heurTrace += "LDV benchmark detected. Setting loop unroll bar to 13.\n" - loopUnrollBar = 13 - staticLoopBound = 64 - elif "standard_strcpy_false-valid-deref_ground_true-termination" in bpl or "960521-1_false-valid-free" in bpl or "960521-1_false-valid-deref" in bpl or "lockfree-3.3" in bpl or "list-ext_false-unreach-call_false-valid-deref" in bpl: - heurTrace += "Memory safety benchmark detected. Setting loop unroll bar to 129.\n" - loopUnrollBar = 129 - elif "is_relaxed_prefix" in bpl: - heurTrace += "Benchmark relax_* detected. Setting loop unroll bar to 15.\n" - loopUnrollBar = 15 - elif "id_o1000_false-unreach-call" in bpl: - heurTrace += "Recursive benchmark detected. Setting loop unroll bar to 1024.\n" - loopUnrollBar = 1024 - elif "n.c24" in bpl or "array_false-unreach-call3" in bpl: - heurTrace += "Loops benchmark detected. Setting loop unroll bar to 1024.\n" - loopUnrollBar = 1024 - elif "printf_false-unreach-call" in bpl or "echo_true-no-overflow" in bpl: - heurTrace += "BusyBox benchmark detected. Setting loop unroll bar to 11.\n" - loopUnrollBar = 11 - elif 'memory-safety' in args.check and "__main($i0" in bpl: - heurTrace += "BusyBox memory safety benchmark detected. Setting loop unroll bar to 4.\n" - loopUnrollBar = 4 - elif 'integer-overflow' in args.check and "__main($i0" in bpl: - heurTrace += "BusyBox overflows benchmark detected. Setting loop unroll bar to 40.\n" - loopUnrollBar = 40 - elif 'integer-overflow' in args.check and ("jain" in bpl or "TerminatorRec02" in bpl or "NonTerminationSimple" in bpl): - heurTrace += "Infinite loop in overflow benchmark. Setting loop unroll bar to INT_MAX.\n" - loopUnrollBar = 2**31 - 1 - elif 'integer-overflow' in args.check and ("(x != 0)" in csource or "(z > 0)" in csource or "(max > 0)" in csource or - "(k < N)" in csource or "partial_sum" in csource): - heurTrace += "Large overflow benchmark. Setting loop unroll bar to INT_MAX.\n" - loopUnrollBar = 2**31 - 1 - elif "i>>16" in csource: - heurTrace += "Large array reach benchmark. Setting loop unroll bar to INT_MAX.\n" - loopUnrollBar = 2**31 - 1 - elif "whoop_poll_table" in csource: - heurTrace += "Large concurrency benchmark. Setting loop unroll bar to INT_MAX.\n" - loopUnrollBar = 2**31 - 1 - - if not "forall" in bpl: - heurTrace += "No quantifiers detected. Setting z3 relevancy to 0.\n" - corral_command += ["/bopt:proverOpt:O:smt.relevancy=0"] + loopUnrollBar = 13 + staticLoopBound = 64 if 'memory-safety' in args.check: if args.prop_to_check == 'valid-deref': From 39bbbc9c35e25e36d55bbf09585abdedf94e7617 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Thu, 15 Oct 2020 21:55:34 -0600 Subject: [PATCH 033/109] Removed testing --- share/smack/svcomp/random_testing.py | 66 ---------------------------- share/smack/svcomp/utils.py | 64 --------------------------- 2 files changed, 130 deletions(-) delete mode 100644 share/smack/svcomp/random_testing.py diff --git a/share/smack/svcomp/random_testing.py b/share/smack/svcomp/random_testing.py deleted file mode 100644 index fa9d09aff..000000000 --- a/share/smack/svcomp/random_testing.py +++ /dev/null @@ -1,66 +0,0 @@ -import re -import os -import smack.top -import subprocess -import sys - -def random_test(args, result): - f = args.input_files[0] - - # test if a file can be tested - with open(f, 'r') as fi: - s = fi.read() - - l = s.split('\n') - if not (len(l) < 20 and len([x for x in l if re.search(r'=\s*__VERIFIER_nondet_uint', x)]) == 1): - return 'abort' - - UMAX_INT = 2**32 - 1 - for i in [8, 4, 2]: - status = compile_and_run(f, s, UMAX_INT/i, args) - if status != 'true': - return status - - return result - -def compile_and_run(f, s, n, args): - s = re.sub("=\s*(__VERIFIER_nondet_uint\(\))", "="+str(n), s) - s = re.sub("__VERIFIER_assert\((.+)\);", "assert(\\1);", s) - s = re.sub(r'(extern )?void reach_error()', '//', s) - s = re.sub(r'(extern )?void __VERIFIER_assume()', '//', s) - s = re.sub(r'reach_error\(\)', 'assert(0)', s) - s = '#include\n' + s - - name = os.path.splitext(os.path.basename(f))[0] - tmp1 = smack.top.temporary_file(name, '.c', args) - with open(tmp1, 'w') as fo: - fo.write(s) - - tmp2 = smack.top.temporary_file(name, '.bin', args) - tmp2 = tmp2.split('/')[-1] - #compile and run - cmd = ['clang', tmp1, '-o', tmp2] - - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - out, err = proc.communicate() - rc = proc.returncode - - if rc: - print('Compiling error') - print(err) - return 'unknown' - else: - cmd = [r'./' + tmp2] - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = proc.communicate() - rc = proc.returncode - if rc: - if re.search(r'Assertion.*failed', err): - return 'false' - else: - print('Execution error') - print(err) - return 'unknown' - else: - return 'true' diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 45d2904f7..143ee1225 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -8,7 +8,6 @@ import smack.frontend from . import filters from .toSVCOMPformat import smackJsonToXmlGraph -from .random_testing import random_test def svcomp_frontend(input_file, args): """Generate Boogie code from SVCOMP-style C-language source(s).""" @@ -249,23 +248,6 @@ def verify_bpl_svcomp(args): heurTrace += "Unrolling made it to a recursion bound of " heurTrace += str(unrollMax) + ".\n" heurTrace += "Reporting benchmark as 'verified'.\n" - if args.execute and not args.pthread: - heurTrace += "Hold on, let's see the execution result.\n" - execution_result = run_binary(args) - heurTrace += "Excecution result is " + execution_result + '\n' - if execution_result != 'true': - heurTrace += "Oops, execution result says {0}.\n".format(execution_result) - if not args.quiet: - print((heurTrace + "\n")) - print(smack.top.results(args)['unknown'][0]) - sys.exit(smack.top.results(args)['unknown'][1]) - random_test_result = random_test(args, result) - if random_test_result == 'false' or random_test_result == 'unknown': - heurTrace += "Oops, random testing says {0}.\n".format(random_test_result) - if not args.quiet: - print((heurTrace + "\n")) - print(smack.top.results(args)['unknown'][0]) - sys.exit(smack.top.results(args)['unknown'][1]) if not args.quiet: print((heurTrace + "\n")) if 'memory-safety' in args.check: @@ -352,49 +334,3 @@ def write_error_file(args, status, verifier_output): with open(args.error_file, 'w') as f: f.write(error.decode('utf-8')) -def run_binary(args): - #process the file to make it runnable - with open(args.input_files[0], 'r') as fi: - s = fi.read() - - s = re.sub(r'(extern )?void reach_error()', '//', s) - s = re.sub(r'reach_error\(\)', 'assert(0)', s) - s = '#include\n' + s - - name = os.path.splitext(os.path.basename(args.input_files[0]))[0] - tmp1 = smack.top.temporary_file(name, '.c', args) - with open(tmp1, 'w') as fo: - fo.write(s) - - tmp2 = smack.top.temporary_file(name, '.bin', args) - tmp2 = tmp2.split('/')[-1] - #compile and run - cmd = ['clang', tmp1, '-o', tmp2] - #cmd += args.clang_options.split() - #if '-m32' in args.clang_options.split(): - #cmd += ['-m32'] - - - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - out, err = proc.communicate() - rc = proc.returncode - - if rc: - print('Compiling error') - print(err) - return 'unknown' - else: - cmd = [r'./' + tmp2] - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = proc.communicate() - rc = proc.returncode - if rc: - if re.search(r'Assertion.*failed', err): - return 'false' - else: - print('Execution error') - print(err) - return 'unknown' - else: - return 'true' From d20d7695f98892963c3b1a154ea5d3722f0e3929 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 16 Oct 2020 19:49:57 -0600 Subject: [PATCH 034/109] Removed dynamic testing part --- share/smack/svcomp/filters.py | 10 +++------- share/smack/svcomp/utils.py | 15 ++++----------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/share/smack/svcomp/filters.py b/share/smack/svcomp/filters.py index 8e0ccda6d..b6a850552 100644 --- a/share/smack/svcomp/filters.py +++ b/share/smack/svcomp/filters.py @@ -34,17 +34,13 @@ def svcomp_filter(f): pruned_lines = raw_file_line_count(lines) raw_lines = len(lines.split('\n')) - executable = False - if raw_lines < 50 and len(linecount(r'__VERIFIER_nondet|fopen', r'void\s+|extern', lines)) == 0 and not ('while(1)' in lines): - executable = True - if bv_filter(lines, raw_lines, pruned_lines): - return 'bitvector', executable + return 'bitvector' if float_filter(lines, raw_lines, pruned_lines): - return 'float', executable + return 'float' - return 'normal', executable + return 'normal' def bv_filter(lines, raw_line_count, pruned_line_count): if ("bugBrokenOut" in lines or "returnsStructure" in lines or "__VERIFIER_nondet_double" in lines or diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 143ee1225..e1fae7395 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -14,8 +14,6 @@ def svcomp_frontend(input_file, args): # enable static LLVM unroll pass args.static_unroll = True - # disable dynamic execution - args.execute = False if len(args.input_files) > 1: raise RuntimeError("Expected a single SVCOMP input file.") @@ -25,19 +23,15 @@ def svcomp_frontend(input_file, args): # fix: disable float filter for memory safety benchmarks if not ('memory-safety' in args.check or 'memleak' in args.check): - # test bv and executable benchmarks - file_type, executable = filters.svcomp_filter(args.input_files[0]) + # figure out category + file_type = filters.svcomp_filter(args.input_files[0]) if file_type == 'bitvector': args.integer_encoding = 'bit-vector' args.pointer_encoding = 'bit-vector' if file_type == 'float' and not 'integer-overflow' in args.check: args.float = True args.integer_encoding = 'bit-vector' - with open(input_file, "r") as sf: - sc = sf.read() - if 'copysign(1' in sc: - args.pointer_encoding = 'bit-vector' - args.execute = executable + args.pointer_encoding = 'bit-vector' else: with open(input_file, "r") as sf: sc = sf.read() @@ -46,7 +40,7 @@ def svcomp_frontend(input_file, args): #args.pointer_encoding = 'bit-vector' if 'memory-safety' in args.check or 'memleak' in args.check or 'integer-overflow' in args.check: - args.strings = True + args.strings = True name, ext = os.path.splitext(os.path.basename(args.input_files[0])) svcomp_process_file(args, name, ext) @@ -70,7 +64,6 @@ def svcomp_frontend(input_file, args): smack.top.link_bc_files([bc],libs,args) def svcomp_check_property(args): - # Check if property is vanilla reachability, and return unknown otherwise if args.svcomp_property: with open(args.svcomp_property, "r") as f: prop = f.read() From 7cdf3d0ba33b421736c5930e78a3b78aa5faf5f2 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 16 Oct 2020 20:02:53 -0600 Subject: [PATCH 035/109] Updated Travis to Ubuntu 20.04 (focal) --- .travis.yml | 6 +++--- bin/build.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0ffdfd721..3dd689375 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: generic os: linux -dist: bionic +dist: focal addons: apt: @@ -49,8 +49,8 @@ before_install: install: - source ./bin/versions - wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - - sudo add-apt-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-${LLVM_SHORT_VERSION} main" - - wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb + - sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${LLVM_SHORT_VERSION} main" + - wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb - sudo dpkg -i packages-microsoft-prod.deb - sudo apt-get install -y apt-transport-https - sudo apt-get update diff --git a/bin/build.sh b/bin/build.sh index c23329073..45ccad045 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -269,7 +269,7 @@ if [ ${INSTALL_DEPENDENCIES} -eq 1 ] && [ "$TRAVIS" != "true" ] ; then sudo add-apt-repository "deb http://apt.llvm.org/${UBUNTU_CODENAME}/ llvm-toolchain-${UBUNTU_CODENAME}-${LLVM_SHORT_VERSION} main" # Adding .NET repository - ${WGET} -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb + ${WGET} -q https://packages.microsoft.com/config/ubuntu/${RELEASE_VERSION}/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb rm -f packages-microsoft-prod.deb sudo apt-get update From 494c0325a9a49ad60bbb6133e3c8c8afd6903950 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sun, 18 Oct 2020 13:14:07 -0600 Subject: [PATCH 036/109] Updated SMACK SVCOMP script --- bin/smack-svcomp-wrapper.sh | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/bin/smack-svcomp-wrapper.sh b/bin/smack-svcomp-wrapper.sh index 2db7b289b..dc709a856 100755 --- a/bin/smack-svcomp-wrapper.sh +++ b/bin/smack-svcomp-wrapper.sh @@ -3,21 +3,12 @@ # This script has to be copied into the root folder of the SVCOMP package ROOT="$( cd "$(dirname "$(readlink -f "${0}")")" && pwd )" -SMACK_BIN="${ROOT}/smack/bin" -BOOGIE_BIN="${ROOT}/boogie" -CORRAL_BIN="${ROOT}/corral" -LOCKPWN_BIN="${ROOT}/lockpwn" -LLVM_BIN="${ROOT}/llvm/bin" -LLVM_LIB="${ROOT}/llvm/lib" +SMACK_BIN="${ROOT}/bin" +BOOGIE_BIN="${ROOT}/smack-deps/boogie" +CORRAL_BIN="${ROOT}/smack-deps/corral" +Z3_BIN="${ROOT}/smack-deps/z3/bin" -# Setting mono heap size to 13GB -export MONO_GC_PARAMS=max-heap-size=13g - -export PATH=${LLVM_BIN}:$SMACK_BIN:$PATH -export BOOGIE="mono ${BOOGIE_BIN}/Boogie.exe" -export CORRAL="mono ${CORRAL_BIN}/corral.exe" -export LOCKPWN="mono ${LOCKPWN_BIN}/lockpwn.exe" -export LD_LIBRARY_PATH=${LLVM_LIB}:$LD_LIBRARY_PATH +export PATH=${SMACK_BIN}:${BOOGIE_BIN}:${CORRAL_BIN}:${Z3_BIN}:$PATH smack -x=svcomp --verifier=svcomp -q $@ From 76c57d26519a328a503bac7fa59ccd2747cc856b Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 19 Oct 2020 09:11:02 -0600 Subject: [PATCH 037/109] Removed check for bit-precise --- share/smack/svcomp/utils.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index e1fae7395..0eefa11dd 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -32,12 +32,6 @@ def svcomp_frontend(input_file, args): args.float = True args.integer_encoding = 'bit-vector' args.pointer_encoding = 'bit-vector' - else: - with open(input_file, "r") as sf: - sc = sf.read() - if "unsigned char b:2" in sc or "4294967294u" in sc or "_ddv_module_init" in sc or "bb_process_escape_sequence" in sc: - args.integer_encoding = 'bit-vector' - #args.pointer_encoding = 'bit-vector' if 'memory-safety' in args.check or 'memleak' in args.check or 'integer-overflow' in args.check: args.strings = True From 039951393495c5cb85bacd98675c6d80cd37952b Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 19 Oct 2020 09:18:39 -0600 Subject: [PATCH 038/109] Removed mem safety checking heuristics --- share/smack/svcomp/utils.py | 116 +++--------------------------------- 1 file changed, 8 insertions(+), 108 deletions(-) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 0eefa11dd..c70c5bec6 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -103,40 +103,6 @@ def verify_bpl_svcomp(args): if not 'memory-safety' in args.check and not 'memleak' in args.check and not 'integer-overflow' in args.check: inject_assert_false(args) - if 'memory-safety' in args.check: - if len(args.check) == 1: - heurTrace = "engage valid deference checks.\n" - args.check.pop() - args.check.append('valid-deref') - args.prop_to_check = 'valid-deref' - args.bpl_with_all_props = smack.top.temporary_file(os.path.splitext(os.path.basename(args.bpl_file))[0], '.bpl', args) - copyfile(args.bpl_file, args.bpl_with_all_props) - smack.top.memsafety_subproperty_selection(args) - args.check.append('memory-safety') - elif 'valid-deref' in args.check: - heurTrace = "engage valid free checks.\n" - args.check.pop() - args.check.pop() - args.prop_to_check = 'valid-free' - args.check.append('valid-free') - args.bpl_file = smack.top.temporary_file(os.path.splitext(os.path.basename(args.bpl_file))[0], '.bpl', args) - copyfile(args.bpl_with_all_props, args.bpl_file) - smack.top.memsafety_subproperty_selection(args) - args.check.append('memory-safety') - elif 'valid-free' in args.check: - heurTrace = "engage memleak checks.\n" - args.check.pop() - args.check.pop() - args.prop_to_check = 'memleak' - args.check.append('memleak') - args.bpl_file = smack.top.temporary_file(os.path.splitext(os.path.basename(args.bpl_file))[0], '.bpl', args) - copyfile(args.bpl_with_all_props, args.bpl_file) - smack.top.memsafety_subproperty_selection(args) - args.check.append('memory-safety') - elif 'memleak' in args.check: - heurTrace = "engage memcleanup checks.\n" - smack.top.memsafety_subproperty_selection(args) - # If pthreads found, perform lock set analysis if args.pthread: lockpwn_command = ["lockpwn"] @@ -176,19 +142,7 @@ def verify_bpl_svcomp(args): # Setting good loop unroll bound based on benchmark class loopUnrollBar = 13 staticLoopBound = 64 - - if 'memory-safety' in args.check: - if args.prop_to_check == 'valid-deref': - if "memleaks_test12_false-valid-free" in bpl: - time_limit = 10 - else: - time_limit = 750 - elif args.prop_to_check == 'valid-free': - time_limit = 80 - elif args.prop_to_check == 'memleak': - time_limit = 50 - else: - time_limit = 880 + time_limit = 880 command = list(corral_command) command += ["/timeLimit:%s" % time_limit] @@ -207,14 +161,6 @@ def verify_bpl_svcomp(args): if not args.quiet: error = smack.top.error_trace(verifier_output, args) print(error) - if 'memory-safety' in args.check: - heurTrace += (args.prop_to_check + "has errors\n") - if args.prop_to_check == 'valid-free': - if args.valid_deref_check_result != 'verified': - force_timeout() - elif args.prop_to_check == 'memleak': - if args.valid_free_check_result == 'timeout': - force_timeout() elif result == 'timeout': #normal inlining heurTrace += "Timed out during normal inlining.\n" @@ -237,23 +183,9 @@ def verify_bpl_svcomp(args): heurTrace += "Reporting benchmark as 'verified'.\n" if not args.quiet: print((heurTrace + "\n")) - if 'memory-safety' in args.check: - heurTrace += (args.prop_to_check + "is verified\n") - if args.prop_to_check == 'valid-deref': - args.valid_deref_check_result = 'verified' - elif args.prop_to_check == 'valid-free': - args.valid_free_check_result = 'verified' - elif args.prop_to_check == 'memleak': - if args.valid_deref_check_result == 'timeout': - force_timeout() - else: - print(smack.top.results(args)[args.valid_deref_check_result][0]) - sys.exit(smack.top.results(args)[args.valid_deref_check_result][1]) - verify_bpl_svcomp(args) - else: - write_error_file(args, 'verified', verifier_output) - print(smack.top.results(args)['verified'][0]) - sys.exit(smack.top.results(args)['verified'][1]) + write_error_file(args, 'verified', verifier_output) + print(smack.top.results(args)['verified'][0]) + sys.exit(smack.top.results(args)['verified'][1]) else: heurTrace += "Only unrolled " + str(unrollMax) + " times.\n" heurTrace += "Insufficient unrolls to consider 'verified'. " @@ -261,48 +193,16 @@ def verify_bpl_svcomp(args): if not args.quiet: print((heurTrace + "\n")) sys.stdout.flush() - if 'memory-safety' in args.check: - heurTrace += (args.prop_to_check + " times out\n") - if args.prop_to_check == 'valid-deref': - args.valid_deref_check_result = 'timeout' - force_timeout() - elif args.prop_to_check == 'valid-free': - args.valid_free_check_result = 'timeout' - elif args.prop_to_check == 'memleak': - if args.valid_deref_check_result == 'timeout': - force_timeout() - else: - print(smack.top.results(args)[args.valid_deref_check_result][0]) - sys.exit(smack.top.results(args)[args.valid_deref_check_result][1]) - verify_bpl_svcomp(args) - else: - force_timeout() + force_timeout() elif result == 'verified': #normal inlining heurTrace += "Normal inlining terminated and found no bugs.\n" else: #normal inlining heurTrace += "Normal inlining returned 'unknown'. See errors above.\n" if not args.quiet: print((heurTrace + "\n")) - if 'memory-safety' in args.check and result == 'verified': - heurTrace += (args.prop_to_check + " is verified\n") - if args.prop_to_check == 'valid-deref': - args.valid_deref_check_result = 'verified' - elif args.prop_to_check == 'valid-free': - args.valid_free_check_result = 'verified' - elif args.prop_to_check == 'memleak': - if args.valid_deref_check_result == 'timeout': - force_timeout() - else: - print(smack.top.results(args)[args.valid_deref_check_result][0]) - sys.exit(smack.top.results(args)[args.valid_deref_check_result][1]) - verify_bpl_svcomp(args) - else: - write_error_file(args, result, verifier_output) - if 'memleak' in args.check and result == 'invalid-memtrack': - sys.exit('SMACK found an error: memory cleanup.') - else: - print(smack.top.results(args)[result][0]) - sys.exit(smack.top.results(args)[result][1]) + write_error_file(args, result, verifier_output) + print(smack.top.results(args)[result][0]) + sys.exit(smack.top.results(args)[result][1]) def write_error_file(args, status, verifier_output): #return From b3b7abf450cbd2915c5ad50c22c6b625c1928b5c Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 19 Oct 2020 15:08:47 -0600 Subject: [PATCH 039/109] Removed support for pthreads benchmarks --- share/smack/svcomp/filters.py | 70 ----------------------------------- share/smack/svcomp/utils.py | 41 ++------------------ 2 files changed, 4 insertions(+), 107 deletions(-) diff --git a/share/smack/svcomp/filters.py b/share/smack/svcomp/filters.py index b6a850552..c2385b9cd 100644 --- a/share/smack/svcomp/filters.py +++ b/share/smack/svcomp/filters.py @@ -138,76 +138,6 @@ def float_filter(lines, raw_line_count, pruned_line_count): return 1 return 1 - -def scrub_pthreads(s): - if 'pthread_create' not in s: - return s, False - - # special case for sequentialized benchmarks - if '__CS_pthread_create' in s: - return s, False - - # special case for machzwd benchmarks - if 'assert_context_process' in s: - return s, False - - #These are strings that will conflict with our pthread header files - #To generate additional strings, copy paste the text. - #Escape all characters that need to be escaped for regex (at least *[]() - # Then replace all newlines and spaces with \s+. Lastly, replace all - # \s+\s+ to \s+. Do this last step until string doesn't change anymore. - fltrs = list() - fltrs.append(r'typedef\s+unsigned\s+long\s+int\s+pthread_t;') - #pthread_attr_t - fltrs.append(r'typedef\s+union\s+{\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_attr_t;') - fltrs.append(r'union\s+pthread_attr_t\s+{\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+};\s+typedef\s+union\s+pthread_attr_t\s+pthread_attr_t;') - #pthread_mutexattr_t - fltrs.append(r'typedef\s+union\s+{\s+char\s+__size\[\d+\];\s+int\s+__align;\s+}\s+pthread_mutexattr_t;') - fltrs.append(r'typedef\s+union\s+{\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_mutexattr_t;') - #pthread_mutex_t - fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__count;\s+int\s+__owner;\s+unsigned\s+int\s+__nusers;\s+int\s+__kind;\s+int\s+__spins;\s+__pthread_list_t\s+__list;\s+}\s+__data;\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_mutex_t;') - fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__count;\s+int\s+__owner;\s+int\s+__kind;\s+unsigned\s+int\s+__nusers;\s+__extension__\s+union\s+{\s+struct\s+{\s+short\s+__espins;\s+short\s+__elision;\s+}\s+__elision_data;\s+__pthread_slist_t\s+__list;\s+};\s+}\s+__data;\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_mutex_t;') - fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__count;\s+int\s+__owner;\s+int\s+__kind;\s+unsigned\s+int\s+__nusers;\s+__extension__\s+union\s+{\s+int\s+__spins;\s+__pthread_slist_t\s+__list;\s+};\s+}\s+__data;\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_mutex_t;') - fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__count;\s+int\s+__owner;\s+unsigned\s+int\s+__nusers;\s+int\s+__kind;\s+short\s+__spins;\s+short\s+__elision;\s+__pthread_list_t\s+__list;\s+# 124 "/usr/include/x86_64-linux-gnu/bits/pthreadtypes\.h" 3 4\s+}\s+__data;\s+\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+} pthread_mutex_t;') - fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__count;\s+int\s+__owner;\s+int\s+__kind;\s+unsigned\s+int\s+__nusers;\s+__extension__\s+union\s+{\s+struct\s+{\s+short\s+__espins;\s+short\s+__elision;\s+}\s+d;\s+__pthread_slist_t\s+__list;\s+};\s+}\s+__data;\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_mutex_t;') - fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__count;\s+int\s+__owner;\s+unsigned\s+int\s+__nusers;\s+int\s+__kind;\s+short\s+__spins;\s+short\s+__elision;\s+__pthread_list_t\s+__list;\s+}\s+__data;\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_mutex_t;') - fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_mutex_s\s+__data;\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_mutex_t;') - #pthread_cond_t - fltrs.append(r'typedef\s+union\s+{\s+struct\s+{\s+int\s+__lock;\s+unsigned\s+int\s+__futex;\s+__extension__\s+unsigned\s+long\s+long\s+int\s+__total_seq;\s+__extension__\s+unsigned\s+long\s+long\s+int\s+__wakeup_seq;\s+__extension__\s+unsigned\s+long\s+long\s+int\s+__woken_seq;\s+void\s+\*__mutex;\s+unsigned\s+int\s+__nwaiters;\s+unsigned\s+int\s+__broadcast_seq;\s+}\s+__data;\s+char\s+__size\[\d+\];\s+__extension__\s+long\s+long\s+int\s+__align;\s+}\s+pthread_cond_t;') - fltrs.append(r'typedef\s+union\s+{\s+struct\s+__pthread_cond_s\s+__data;\s+char\s+__size\[\d+\];\s+__extension__\s+long\s+long\s+int\s+__align;\s+}\s+pthread_cond_t;') - #pthread_condattr_t - fltrs.append(r'typedef\s+union\s+{\s+char\s+__size\[\d+\];\s+int\s+__align;\s+}\s+pthread_condattr_t;') - fltrs.append(r'typedef\s+union\s+{\s+char\s+__size\[\d+\];\s+long\s+int\s+__align;\s+}\s+pthread_condattr_t;') - #enums - fltrs.append(r'enum\s+{\s+PTHREAD_MUTEX_TIMED_NP,\s+PTHREAD_MUTEX_RECURSIVE_NP,\s+PTHREAD_MUTEX_ERRORCHECK_NP,\s+PTHREAD_MUTEX_ADAPTIVE_NP\s+,\s+PTHREAD_MUTEX_NORMAL\s+=\s+PTHREAD_MUTEX_TIMED_NP,\s+PTHREAD_MUTEX_RECURSIVE\s+=\s+PTHREAD_MUTEX_RECURSIVE_NP,\s+PTHREAD_MUTEX_ERRORCHECK\s+=\s+PTHREAD_MUTEX_ERRORCHECK_NP,\s+PTHREAD_MUTEX_DEFAULT\s+=\s+PTHREAD_MUTEX_NORMAL\s+};') - fltrs.append(r'enum\s+{\s+PTHREAD_MUTEX_TIMED_NP,\s+PTHREAD_MUTEX_RECURSIVE_NP,\s+PTHREAD_MUTEX_ERRORCHECK_NP,\s+PTHREAD_MUTEX_ADAPTIVE_NP\s+};') - #pthread_cond_init decl - fltrs.append(r'extern\s+int\s+pthread_cond_init\s+\(pthread_cond_t\s+\*__restrict\s+__cond,\s+__const\s+pthread_condattr_t\s+\*__restrict\s+__cond_attr\)\s+__attribute__\s+\(\(__nothrow__\s+,\s+__leaf__\)\)\s+__attribute__\s+\(\(__nonnull__\s+\(\d+\)\)\);') - fltrs.append(r'extern\s+int\s+pthread_cond_init\s*\(pthread_cond_t\s+\*__restrict\s+__cond,\s+const\s+pthread_condattr_t\s+\*__restrict\s+__cond_attr\)\s+__attribute__\s*\(\(__nothrow__\s+,\s+__leaf__\)\)\s+__attribute__\s+\(\(__nonnull__\s+\(1\)\)\);') - fltrs.append(r'extern\s+int\s+pthread_cond_init\s*\(pthread_cond_t\s+\*__restrict\s+__cond,\s+__const\s+pthread_condattr_t\s+\*__restrict\s+__cond_attr\)\s+__attribute__\s+\(\(__nothrow__\)\)\s+__attribute__\s+\(\(__nonnull__\s+\(1\)\)\);') - #__VERIFIER_atomic_begin definition removal - fltrs.append(r'int\s+__global_lock;\s+void\s+__VERIFIER_atomic_begin\(\)\s+{\s+__VERIFIER_assume\(__global_lock==0\);\s+__global_lock=1;\s+return;\s+}\s+void\s+__VERIFIER_atomic_end\(\)\s+{\s+__VERIFIER_assume\(__global_lock==1\);\s+__global_lock=0;\s+return;\s+}') - - - #Remove each occurrence - for fltr in fltrs: - #sold = s - pat = re.compile(fltr, re.MULTILINE); - s = pat.sub('', s) - #if sold == s: - # print("Didn't match - " + fltr) - #else: - # print("DID match - " + fltr) - - s = re.sub(r'(__VERIFIER_atomic_((?!begin|end).)*?\(.*?\);)', - r'__VERIFIER_atomic_begin(); \1 __VERIFIER_atomic_end();', - s) - - s = re.sub(r'\ninline ', r'\n', s) - - return s, True - - if __name__ == '__main__': print("What?") print(svcomp_filter(sys.argv[1])) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index c70c5bec6..f2d27852f 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -37,7 +37,6 @@ def svcomp_frontend(input_file, args): args.strings = True name, ext = os.path.splitext(os.path.basename(args.input_files[0])) - svcomp_process_file(args, name, ext) args.clang_options += " -fbracket-depth=2048" args.clang_options += " -Wno-unknown-attributes" @@ -71,20 +70,6 @@ def svcomp_check_property(args): print(smack.top.results(args)['unknown'][0]) sys.exit(smack.top.results(args)['unknown'][1]) -def svcomp_process_file(args, name, ext): - args.orig_files = list(args.input_files) - with open(args.input_files[0], 'r') as fi: - s = fi.read() - args.input_files[0] = smack.top.temporary_file(name, ext, args) - - #Remove any preprocessed declarations of pthread types - #Also, if file contains 'pthread', set pthread mode - s,args.pthread = filters.scrub_pthreads(s) - if args.pthread: - s = "#include \n" + s - with open(args.input_files[0], 'w') as fo: - fo.write(s) - def force_timeout(): sys.stdout.flush() time.sleep(1000) @@ -103,15 +88,6 @@ def verify_bpl_svcomp(args): if not 'memory-safety' in args.check and not 'memleak' in args.check and not 'integer-overflow' in args.check: inject_assert_false(args) - # If pthreads found, perform lock set analysis - if args.pthread: - lockpwn_command = ["lockpwn"] - lockpwn_command += [args.bpl_file] - lockpwn_command += ["/corral"] - args.bpl_file = smack.top.temporary_file(os.path.splitext(os.path.basename(args.bpl_file))[0], '.bpl', args) - lockpwn_command += ["/o:%s" % args.bpl_file] - lockpwn_output = smack.top.try_command(lockpwn_command); - corral_command = ["corral"] corral_command += [args.bpl_file] corral_command += ["/tryCTrace", "/noTraceOnDisk", "/printDataValues:1"] @@ -125,19 +101,10 @@ def verify_bpl_svcomp(args): with open(args.input_files[0], "r") as f: csource = f.read() - if args.pthread: - if "fib_bench" in bpl or "27_Boop_simple_vf_false-unreach-call" in bpl or "k < 5;" in csource or "k < 10;" in csource or "k < 20;" in csource: - heurTrace += "Increasing context switch bound for certain pthread benchmarks.\n" - corral_command += ["/k:30"] - else: - corral_command += ["/k:3"] - if not "qrcu_reader2" in bpl and not "__VERIFIER_atomic_take_write_lock" in bpl and not "fib_bench" in bpl: - corral_command += ["/cooperative"] - else: - corral_command += ["/k:1"] - if not ('memory-safety' in args.check or args.integer_encoding == 'bit-vector' or 'memleak' in args.check): - if not ("dll_create" in csource or "sll_create" in csource or "changeMethaneLevel" in csource): - corral_command += ["/di"] + corral_command += ["/k:1"] + if not ('memory-safety' in args.check or args.integer_encoding == 'bit-vector' or 'memleak' in args.check): + if not ("dll_create" in csource or "sll_create" in csource or "changeMethaneLevel" in csource): + corral_command += ["/di"] # Setting good loop unroll bound based on benchmark class loopUnrollBar = 13 From f9b5843008626ce090db80d4c4cd6da8ad7d05ae Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 19 Oct 2020 15:14:49 -0600 Subject: [PATCH 040/109] Removed float and bit-vector filters to set these options --- share/smack/svcomp/filters.py | 144 ---------------------------------- share/smack/svcomp/utils.py | 23 ++---- 2 files changed, 5 insertions(+), 162 deletions(-) delete mode 100644 share/smack/svcomp/filters.py diff --git a/share/smack/svcomp/filters.py b/share/smack/svcomp/filters.py deleted file mode 100644 index c2385b9cd..000000000 --- a/share/smack/svcomp/filters.py +++ /dev/null @@ -1,144 +0,0 @@ -import sys -import re -import subprocess - -def linecount(p1, p2, s): - valid_lines = [] - lines = s.split('\n') - regex_p1 = re.compile(p1) - regex_p2 = re.compile(p2) - for line in lines: - r1 = regex_p1.search(line) - if r1: - r2 = regex_p2.search(line) - if r2 is None: - valid_lines.append(r1.group(0)) - return valid_lines - -def raw_file_line_count(s): - lines = s.split('\n') - count = 0 - #grep -v extern | grep -vP "^\w*$" | grep -v "#" - crap = re.compile(r"""(extern|^\w*$|#)""") - for line in lines: - if crap.search(line) is None: - count += 1 - - return count - -def svcomp_filter(f): - lines = None - with open(f, 'r') as inputfile: - lines = inputfile.read() - - pruned_lines = raw_file_line_count(lines) - raw_lines = len(lines.split('\n')) - - if bv_filter(lines, raw_lines, pruned_lines): - return 'bitvector' - - if float_filter(lines, raw_lines, pruned_lines): - return 'float' - - return 'normal' - -def bv_filter(lines, raw_line_count, pruned_line_count): - if ("bugBrokenOut" in lines or "returnsStructure" in lines or "__VERIFIER_nondet_double" in lines or - "__VERIFIER_nondet_float" in lines or "0x43300000" in lines or "float X, P;" in lines or "1415926538837245" in lines or - "huge_floor" in lines or "huge_ceil" in lines or "tiny_sqrt" in lines or "fmax_float" in lines or - "fabs_double" in lines or "round_double" in lines or "trunc_double" in lines or "zero_log" in lines or - "isinf_float" in lines or "trunc_float" in lines or "exponent_less_127" in lines): - return 0 - elif ('4294967294u' in lines or '616783' in lines or '__main(argc' in lines): - return 1 - - if raw_line_count > 1500: - if 'ldv_usb_gadget' in lines or "SyncPush" in lines or "kaweth_set_receive_filter" in lines: - return 1 - else: - return 0 - - #line_count = raw_file_line_count(lines) - if pruned_line_count > 650: - return 0 - - #special case for Concurrent benchmarks - if "pthread_create" in lines: - return 0 - - #cast patterns - if pruned_line_count <= 210: - - if pruned_line_count < 25 and 'while(1)' in lines: - return 1 - - casts = re.compile(r'''4294967295|plus_one|minus_one|\(x % 2\) == \(y % 2\)|linear_search|while \(\('0' <= c\) && \(c <= '9'\)\)''') - if casts.search(lines): - return 1 - #bwops = re.compile(r'''[^\&]\&[^\&]|[^\|]\|[^\|]|\^|>>|<<''') - bwops = re.compile(r'''[=|\(][^,]*[^\&|\(|{]\&\s|[^\|]\|\s|\^|>>|<<''') - #bwops = re.compile(r'''\s\&\s|\s\|\s|\^|>>|<<''') - #dv = re.compile(r'''1\s+<<\s+[1|5]|cil''') - dv = re.compile(r'''1.*<<.*\"|cil|found|node''') - - for line in lines.split('\n'): - if bwops.search(line): - if dv.search(line) is None: - #print line - return 1 - #print raw_file_line_count(lines) - return 0 - -def float_filter(lines, raw_line_count, pruned_line_count): - fliteral = 0 - ddecl = 0 - - if ("bugBrokenOut" in lines or "returnsStructure" in lines or "__VERIFIER_nondet_double" in lines or - "__VERIFIER_nondet_float" in lines or "0x43300000" in lines or "float X, P;" in lines or "1415926538837245" in lines or - "huge_floor" in lines or "huge_ceil" in lines or "tiny_sqrt" in lines or "fmax_float" in lines or - "fabs_double" in lines or "round_double" in lines or "trunc_double" in lines or "zero_log" in lines or - "isinf_float" in lines or "trunc_float" in lines or "exponent_less_127" in lines): - return 1 - - #heuristic #-1: don't do test on too large programs - if raw_line_count >= 2000: - return 0 - #heuristic #0: more than Float.set maximum LOC ==> not - if pruned_line_count > 140: #(138 = maximum) - return 0 - #heuristic #1: __VERIFIER_nondet ==> float category - result = re.search(r"""(__VERIFIER_nondet_(float|double)|ieee754_float)""", lines) - if result: - return 1 - - #heuristic #2: check float literal # - valid_lines = linecount(r"""(0x)?\d+\.\d*(f|p|e)?""", r"""#|line|June|CIL|0\.000000|\"\d+|Created""", lines) - count = len(valid_lines) - if count > 60: - return 0 - if count == 0: - #heuristic #3: check double - #result = re.search(r"""0x\d+\.?.*p|double""", lines) - result = re.search(r"""double""", lines) - if result: - return 1 - else: - return 0 - else: - #heuristic #4: for loops/heapmanipulation - #print valid_lines - regex_special = re.compile(r"""1\.4p|1\.0e""") - for valid_line in valid_lines: - if regex_special.search(valid_line) is not None and count <= 4: - return 0 - if valid_line == '1.' or valid_line == '2.': - if 'double' not in lines: - return 0 - else: - return 1 - return 1 - -if __name__ == '__main__': - print("What?") - print(svcomp_filter(sys.argv[1])) - diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index f2d27852f..7ef5168bb 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -6,7 +6,6 @@ from shutil import copyfile import smack.top import smack.frontend -from . import filters from .toSVCOMPformat import smackJsonToXmlGraph def svcomp_frontend(input_file, args): @@ -21,18 +20,6 @@ def svcomp_frontend(input_file, args): # check svcomp properties and set flags accordingly svcomp_check_property(args) - # fix: disable float filter for memory safety benchmarks - if not ('memory-safety' in args.check or 'memleak' in args.check): - # figure out category - file_type = filters.svcomp_filter(args.input_files[0]) - if file_type == 'bitvector': - args.integer_encoding = 'bit-vector' - args.pointer_encoding = 'bit-vector' - if file_type == 'float' and not 'integer-overflow' in args.check: - args.float = True - args.integer_encoding = 'bit-vector' - args.pointer_encoding = 'bit-vector' - if 'memory-safety' in args.check or 'memleak' in args.check or 'integer-overflow' in args.check: args.strings = True @@ -75,11 +62,11 @@ def force_timeout(): time.sleep(1000) def inject_assert_false(args): - with open(args.bpl_file, 'r') as bf: - content = bf.read() - content = content.replace('call reach_error();', 'assert false; call reach_error();') - with open(args.bpl_file, 'w') as bf: - bf.write(content) + with open(args.bpl_file, 'r') as bf: + content = bf.read() + content = content.replace('call reach_error();', 'assert false; call reach_error();') + with open(args.bpl_file, 'w') as bf: + bf.write(content) def verify_bpl_svcomp(args): """Verify the Boogie source file using SVCOMP-tuned heuristics.""" From 597201f15622c81de902ade720e24904fc7dab90 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 19 Oct 2020 15:18:21 -0600 Subject: [PATCH 041/109] Minor clean up --- share/smack/svcomp/utils.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 7ef5168bb..5b4a6356c 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -82,9 +82,6 @@ def verify_bpl_svcomp(args): corral_command += ["/bopt:proverOpt:O:smt.qi.eager_threshold=100"] corral_command += ["/bopt:proverOpt:O:smt.arith.solver=2"] - with open(args.bpl_file, "r") as f: - bpl = f.read() - with open(args.input_files[0], "r") as f: csource = f.read() From cbaaa0b3569953ba1acf4f3b8908822fd88aa1df Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Tue, 20 Oct 2020 15:09:07 -0600 Subject: [PATCH 042/109] Reversing a small change - we need this field Field orig_files is used by witness generator somehow. --- share/smack/svcomp/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 5b4a6356c..26f2b3dec 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -24,6 +24,7 @@ def svcomp_frontend(input_file, args): args.strings = True name, ext = os.path.splitext(os.path.basename(args.input_files[0])) + args.orig_files = list(args.input_files) args.clang_options += " -fbracket-depth=2048" args.clang_options += " -Wno-unknown-attributes" From dc5c73b21e84968a9d792c04e052e5d78092e0f4 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 21 Oct 2020 00:12:38 -0600 Subject: [PATCH 043/109] Fixes --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d72dabd5..71831af2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,7 +131,6 @@ add_library(smackTranslator STATIC include/smack/VectorOperations.h include/smack/MemorySafetyChecker.h include/smack/IntegerOverflowChecker.h - include/smack/RustFixes.h include/smack/NormalizeLoops.h include/smack/RustFixes.h include/smack/SplitAggregateValue.h @@ -157,7 +156,6 @@ add_library(smackTranslator STATIC lib/smack/VectorOperations.cpp lib/smack/MemorySafetyChecker.cpp lib/smack/IntegerOverflowChecker.cpp - lib/smack/RustFixes.cpp lib/smack/NormalizeLoops.cpp lib/smack/RustFixes.cpp lib/smack/SplitAggregateValue.cpp From 5029c384d9121c2f5f784c9c6b1d982c239aab52 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 21 Oct 2020 00:16:44 -0600 Subject: [PATCH 044/109] Remove --- share/smack/versions.py | 1 - 1 file changed, 1 deletion(-) delete mode 100644 share/smack/versions.py diff --git a/share/smack/versions.py b/share/smack/versions.py deleted file mode 100644 index ba8154688..000000000 --- a/share/smack/versions.py +++ /dev/null @@ -1 +0,0 @@ -VERSIONS = {'RUST_VERSION': 'nightly-2020-08-23'} From bf4b1e351126da2a7f6e03486bdfc54706b0ab43 Mon Sep 17 00:00:00 2001 From: vagrant Date: Wed, 21 Oct 2020 06:50:18 +0000 Subject: [PATCH 045/109] Fixes --- share/smack/frontend.py | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 76b64899a..178bfdd27 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -5,6 +5,11 @@ from .utils import temporary_file, try_command, temporary_directory from .versions import RUST_VERSION +# Needed for cargo operations +try: + import toml +except: + pass def languages(): """A dictionary of languages per file extension.""" @@ -268,30 +273,6 @@ def json_compilation_database_frontend(input_file, args): llvm_to_bpl(args) -def is_cargo_included_bc(name, args): - if not (len(name) > 3 and name[-3:] == '.bc'): - return False - - if name.startswith('smack-'): - # This is an artifact of the build process - return True - - if ',' in args.crates: - crates = list(args.crates.split(',')) - - else: - crates = [args.crates] - # Cargo replaces '-' in crate names with '_'. This is for - # convenience. - crates = set(map(lambda x: x.replace('-', '_'), crates)) - - for crate in crates: - if name.startswith(crate + '-'): - return True - - return False - - def default_cargo_compile_command(args): compile_command = [ 'cargo', @@ -314,13 +295,15 @@ def cargo_frontend(input_file, args): try_command(compile_command, console=True, env={'RUSTFLAGS': " ".join(rustargs)}) - # Get crate bc files - bcbase = targetdir+'/debug/deps/' + crate_name = toml.load(input_file)['package']['name'].replace('-', '_') + + # Find the name of the crate's bc file + bcbase = targetdir + '/debug/deps/' entries = os.listdir(bcbase) bcs = [] for entry in entries: - if is_cargo_included_bc(entry, args): + if entry.startswith(crate_name + '-') and entry.endswith('.bc'): bcs.append(bcbase + entry) bc_file = temporary_file( From 15acdf04096c00f9772120a6e2a1ac9cbeddcd13 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 21 Oct 2020 01:02:17 -0600 Subject: [PATCH 046/109] Flake8 --- share/smack/frontend.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 178bfdd27..e845756e1 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -8,9 +8,10 @@ # Needed for cargo operations try: import toml -except: +except ImportError: pass + def languages(): """A dictionary of languages per file extension.""" return { @@ -296,7 +297,7 @@ def cargo_frontend(input_file, args): env={'RUSTFLAGS': " ".join(rustargs)}) crate_name = toml.load(input_file)['package']['name'].replace('-', '_') - + # Find the name of the crate's bc file bcbase = targetdir + '/debug/deps/' entries = os.listdir(bcbase) @@ -314,6 +315,7 @@ def cargo_frontend(input_file, args): try_command(['llvm-link'] + bcs + ['-o', bc_file]) return bc_file + def default_rust_compile_args(args): return ['-A', 'unused-imports', @@ -327,6 +329,7 @@ def default_rust_compile_args(args): '-C', 'passes=name-anon-globals'] + def default_rust_compile_command(args): compile_command = (['rustc', '+' + RUST_VERSION] + default_rust_compile_args(args)) From 60f8772c555eccdc898dad02850a4cad053eec3a Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 21 Oct 2020 01:10:49 -0600 Subject: [PATCH 047/109] Update --- examples/rust-cargo/Cargo.toml | 2 +- examples/rust-cargo/src/main.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/rust-cargo/Cargo.toml b/examples/rust-cargo/Cargo.toml index ffb44d503..164489e7f 100644 --- a/examples/rust-cargo/Cargo.toml +++ b/examples/rust-cargo/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -smack = { path = "../../smack"} +smack = { path = "/usr/local/share/smack/lib/smack" } [profile.dev] incremental=false diff --git a/examples/rust-cargo/src/main.rs b/examples/rust-cargo/src/main.rs index 9a1f74226..b21f50b6d 100644 --- a/examples/rust-cargo/src/main.rs +++ b/examples/rust-cargo/src/main.rs @@ -5,7 +5,7 @@ use smack::*; // @expect error fn main() { - let a = 2; - let b = 3; + let a: u32 = 2.verifier_nondet(); + let b: u32 = 3.verifier_nondet(); smack::assert!(a + b != 5); } From da2fe6197a5bafa9a10b14ec230a4817cab05d65 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 21 Oct 2020 17:26:52 -0600 Subject: [PATCH 048/109] Smack lib fixes --- CMakeLists.txt | 6 + share/smack/include/smack.h | 4 + share/smack/lib/smack.c | 33 +- share/smack/lib/smack/src/smack.c | 545 ------------------------------ share/smack/lib/smack/src/smack.h | 178 ---------- 5 files changed, 42 insertions(+), 724 deletions(-) delete mode 100644 share/smack/lib/smack/src/smack.c delete mode 100644 share/smack/lib/smack/src/smack.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 71831af2c..eca095bc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,3 +213,9 @@ INSTALL(FILES DESTINATION share/smack RENAME versions.py ) + +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/share/smack/include/smack.h + ${CMAKE_CURRENT_SOURCE_DIR}/share/smack/lib/smack.c + DESTINATION share/smack/smack/src +) diff --git a/share/smack/include/smack.h b/share/smack/include/smack.h index 19f755c50..4d2c40064 100644 --- a/share/smack/include/smack.h +++ b/share/smack/include/smack.h @@ -84,6 +84,10 @@ void __VERIFIER_assert(int); #define U(...) TY(__VA_ARGS__, U4, U3, U2, U1)(__VA_ARGS__) #define NONDET_DECL(P, ty...) S(ty) U(P, U(ty))(void) +#define EMPTY_NONDET_DEFN(P, ty...) S(ty) U(P, U(ty))(void) { \ + ty x; \ + return x; \ +} void *__VERIFIER_nondet(void); NONDET_DECL(__SMACK_nondet, char); diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index 61c7651c0..37d908333 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -34,19 +34,50 @@ */ void __VERIFIER_assume(int x) { +#if !RUST_EXEC __SMACK_dummy(x); __SMACK_code("assume @ != $0;", x); +#endif } #ifndef CUSTOM_VERIFIER_ASSERT void __VERIFIER_assert(int x) { -#if !MEMORY_SAFETY && !SIGNED_INTEGER_OVERFLOW_CHECK +#if !MEMORY_SAFETY && !SIGNED_INTEGER_OVERFLOW_CHECK && !RUST_EXEC __SMACK_dummy(x); __SMACK_code("assert @ != $0;", x); #endif } #endif +#if RUST_EXEC +// Enable compatibility with Cargo compilation. +EMPTY_NONDET_DEFN(__SMACK_nondet, char); +EMPTY_NONDET_DEFN(__SMACK_nondet, signed, char); +EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, char); +EMPTY_NONDET_DEFN(__SMACK_nondet, short); +EMPTY_NONDET_DEFN(__SMACK_nondet, short, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, signed, short); +EMPTY_NONDET_DEFN(__SMACK_nondet, signed, short, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, short); +EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, short, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, signed, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned); +EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, long); +EMPTY_NONDET_DEFN(__SMACK_nondet, long, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, signed, long); +EMPTY_NONDET_DEFN(__SMACK_nondet, signed, long, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long); +EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, long, long); +EMPTY_NONDET_DEFN(__SMACK_nondet, long, long, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, signed, long, long); +EMPTY_NONDET_DEFN(__SMACK_nondet, signed, long, long, int); +EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long); +EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long, int); +#endif // RUST_EXEC + void __SMACK_check_overflow(int flag) { __SMACK_dummy(flag); __SMACK_code("assert {:overflow} @ == $0;", flag); diff --git a/share/smack/lib/smack/src/smack.c b/share/smack/lib/smack/src/smack.c deleted file mode 100644 index 7b3bcf7df..000000000 --- a/share/smack/lib/smack/src/smack.c +++ /dev/null @@ -1,545 +0,0 @@ -// -// This file is distributed under the MIT License. See LICENSE for details. -// -#include -#include -#include -#include -#include - -/** - * The SMACK "prelude" definitions - * - * TODO add more documentation - * - * NOTES ON MEMORY MODELS - * - * 1. addresses are (unbounded) integers - * 2. one unbounded integer is stored at each address - * 3. (NO-REUSE only) heap addresses are allocated in a strictly increasing - * fashion - * 4. (NO-REUSE only) freed (heap) addresses are never reallocated - * 5. the address space is partitioned as follows - * - * Address A Allocation - * --------- ---------- - * A > 0 Heap - * A = 0 Not allocated (null) - * $GLOBALS_BOTTOM <= A < 0 Static (global storage) - * $GLOBALS_BOTTOM - 32768 <= A < $GLOBALS_BOTTOM Not allocated (padding) - * $EXTERNS_BOTTOM <= A < $GLOBALS_BOTTOM - 32768 External globals - * A < $EXTERNS_BOTTOM Objects returned from - * external functions - * - */ - -void __VERIFIER_assume(int x) { -#if !RUST_EXEC - __SMACK_dummy(x); - __SMACK_code("assume @ != $0;", x); -#endif -} - -#ifndef CUSTOM_VERIFIER_ASSERT -void __VERIFIER_assert(int x) { -#if !MEMORY_SAFETY && !SIGNED_INTEGER_OVERFLOW_CHECK && !RUST_EXEC - __SMACK_dummy(x); - __SMACK_code("assert @ != $0;", x); -#endif -} -#endif - -void __SMACK_check_overflow(int flag) { - __SMACK_dummy(flag); - __SMACK_code("assert {:overflow} @ == $0;", flag); -} - -char __VERIFIER_nondet_char(void) { - char x = __SMACK_nondet_char(); - __VERIFIER_assume(x >= SCHAR_MIN && x <= SCHAR_MAX); - return x; -} - -signed char __VERIFIER_nondet_signed_char(void) { - signed char x = __SMACK_nondet_signed_char(); - __VERIFIER_assume(x >= SCHAR_MIN && x <= SCHAR_MAX); - return x; -} - -unsigned char __VERIFIER_nondet_unsigned_char(void) { - unsigned char x = __SMACK_nondet_unsigned_char(); - __VERIFIER_assume(x >= 0 && x <= UCHAR_MAX); - return x; -} - -short __VERIFIER_nondet_short(void) { - short x = __SMACK_nondet_short(); - __VERIFIER_assume(x >= SHRT_MIN && x <= SHRT_MAX); - return x; -} - -signed short __VERIFIER_nondet_signed_short(void) { - signed short x = __SMACK_nondet_signed_short(); - __VERIFIER_assume(x >= SHRT_MIN && x <= SHRT_MAX); - return x; -} - -signed short int __VERIFIER_nondet_signed_short_int(void) { - signed short int x = __SMACK_nondet_signed_short_int(); - __VERIFIER_assume(x >= SHRT_MIN && x <= SHRT_MAX); - return x; -} - -unsigned short __VERIFIER_nondet_unsigned_short(void) { - unsigned short x = __SMACK_nondet_unsigned_short(); - __VERIFIER_assume(x >= 0 && x <= USHRT_MAX); - return x; -} - -unsigned short int __VERIFIER_nondet_unsigned_short_int(void) { - unsigned short int x = __SMACK_nondet_unsigned_short_int(); - __VERIFIER_assume(x >= 0 && x <= USHRT_MAX); - return x; -} - -int __VERIFIER_nondet_int(void) { -#if !RUST_EXEC - int x = __SMACK_nondet_int(); - __VERIFIER_assume(x >= INT_MIN && x <= INT_MAX); - return x; -#endif - return 0; -} - -signed int __VERIFIER_nondet_signed_int(void) { - signed int x = __SMACK_nondet_signed_int(); - __VERIFIER_assume(x >= INT_MIN && x <= INT_MAX); - return x; -} - -unsigned __VERIFIER_nondet_unsigned(void) { - unsigned x = __SMACK_nondet_unsigned(); - unsigned min = __SMACK_nondet_unsigned(); - unsigned max = __SMACK_nondet_unsigned(); - __VERIFIER_assume(min == 0 && max >= UINT_MAX && max <= UINT_MAX); - __VERIFIER_assume(x >= min && x <= max); - return x; -} - -unsigned int __VERIFIER_nondet_unsigned_int(void) { -#if !RUST_EXEC - unsigned int x = __SMACK_nondet_unsigned_int(); - unsigned int min = __SMACK_nondet_unsigned_int(); - unsigned int max = __SMACK_nondet_unsigned_int(); - __VERIFIER_assume(min == 0 && max >= UINT_MAX && max <= UINT_MAX); - __VERIFIER_assume(x >= min && x <= max); - return x; -#endif - return 0; -} - -long __VERIFIER_nondet_long(void) { - long x = __SMACK_nondet_long(); - __VERIFIER_assume(x >= LONG_MIN && x <= LONG_MAX); - return x; -} - -long int __VERIFIER_nondet_long_int(void) { - long int x = __SMACK_nondet_long_int(); - __VERIFIER_assume(x >= LONG_MIN && x <= LONG_MAX); - return x; -} - -signed long __VERIFIER_nondet_signed_long(void) { - signed long x = __SMACK_nondet_signed_long(); - __VERIFIER_assume(x >= LONG_MIN && x <= LONG_MAX); - return x; -} - -signed long int __VERIFIER_nondet_signed_long_int(void) { - signed long int x = __SMACK_nondet_signed_long_int(); - __VERIFIER_assume(x >= LONG_MIN && x <= LONG_MAX); - return x; -} - -unsigned long __VERIFIER_nondet_unsigned_long(void) { - unsigned long x = __SMACK_nondet_unsigned_long(); - unsigned long min = __SMACK_nondet_unsigned_long(); - unsigned long max = __SMACK_nondet_unsigned_long(); - __VERIFIER_assume(min == 0 && max >= ULONG_MAX && max <= ULONG_MAX); - __VERIFIER_assume(x >= min && x <= max); - return x; -} - -unsigned long int __VERIFIER_nondet_unsigned_long_int(void) { - unsigned long int x = __SMACK_nondet_unsigned_long_int(); - unsigned long int min = __SMACK_nondet_unsigned_long_int(); - unsigned long int max = __SMACK_nondet_unsigned_long_int(); - __VERIFIER_assume(min == 0 && max >= ULONG_MAX && max <= ULONG_MAX); - __VERIFIER_assume(x >= min && x <= max); - return x; -} - -long long __VERIFIER_nondet_long_long(void) { - long long x = __SMACK_nondet_long_long(); - __VERIFIER_assume(x >= LLONG_MIN && x <= LLONG_MAX); - return x; -} - -long long int __VERIFIER_nondet_long_long_int(void) { - long long int x = __SMACK_nondet_long_long_int(); - __VERIFIER_assume(x >= LLONG_MIN && x <= LLONG_MAX); - return x; -} - -signed long long __VERIFIER_nondet_signed_long_long(void) { - signed long long x = __SMACK_nondet_signed_long_long(); - __VERIFIER_assume(x >= LLONG_MIN && x <= LLONG_MAX); - return x; -} - -signed long long int __VERIFIER_nondet_signed_long_long_int(void) { - signed long long int x = __SMACK_nondet_signed_long_long_int(); - __VERIFIER_assume(x >= LLONG_MIN && x <= LLONG_MAX); - return x; -} - -unsigned long long __VERIFIER_nondet_unsigned_long_long(void) { - unsigned long long x = __SMACK_nondet_unsigned_long_long(); - unsigned long long min = __SMACK_nondet_unsigned_long_long(); - unsigned long long max = __SMACK_nondet_unsigned_long_long(); - __VERIFIER_assume(min == 0 && max >= ULLONG_MAX && max <= ULLONG_MAX); - __VERIFIER_assume(x >= min && x <= max); - return x; -} - -unsigned long long int __VERIFIER_nondet_unsigned_long_long_int(void) { - unsigned long long int x = __SMACK_nondet_unsigned_long_long_int(); - unsigned long long int min = __SMACK_nondet_unsigned_long_long_int(); - unsigned long long int max = __SMACK_nondet_unsigned_long_long_int(); - __VERIFIER_assume(min == 0 && max >= ULLONG_MAX && max <= ULLONG_MAX); - __VERIFIER_assume(x >= min && x <= max); - return x; -} - -// Used in SVCCOMP benchmarks - -_Bool __VERIFIER_nondet_bool(void) { - _Bool x = (_Bool)__VERIFIER_nondet_int(); - __VERIFIER_assume(x == 0 || x == 1); - return x; -} - -unsigned char __VERIFIER_nondet_uchar(void) { - unsigned char x = __VERIFIER_nondet_unsigned_char(); - return x; -} - -unsigned short __VERIFIER_nondet_ushort(void) { - unsigned short x = __VERIFIER_nondet_unsigned_short(); - return x; -} - -unsigned int __VERIFIER_nondet_uint(void) { - unsigned int x = __VERIFIER_nondet_unsigned_int(); - return x; -} - -unsigned long __VERIFIER_nondet_ulong(void) { - unsigned long x = __VERIFIER_nondet_unsigned_long(); - return x; -} - -void *__VERIFIER_nondet_pointer(void) { return __VERIFIER_nondet(); } - -void __SMACK_dummy(int v) { __SMACK_code("assume true;"); } - -#define D(d) __SMACK_top_decl(d) - -void __SMACK_decls(void) { - // Memory debugging symbols - D("type $mop;"); - D("procedure boogie_si_record_mop(m: $mop);"); - D("const $MOP: $mop;"); - - D("var $exn: bool;"); - D("var $exnv: int;"); - - // Concurrency primitives - D("procedure corral_atomic_begin();"); - D("procedure corral_atomic_end();"); - - D("procedure $alloc(n: ref) returns (p: ref)\n" - "{\n" - " call corral_atomic_begin();\n" - " call p := $$alloc(n);\n" - " call corral_atomic_end();\n" - "}\n"); - -#if MEMORY_SAFETY - __SMACK_dummy((int)__SMACK_check_memory_safety); - D("implementation __SMACK_check_memory_safety(p: ref, size: ref)\n" - "{\n" - " assert {:valid_deref} $Alloc[$base(p)];\n" - " assert {:valid_deref} $sle.ref.bool($base(p), p);\n" -#if MEMORY_MODEL_NO_REUSE_IMPLS - " assert {:valid_deref} $sle.ref.bool($add.ref(p, size), " - "$add.ref($base(p), $Size($base(p))));\n" -#elif MEMORY_MODEL_REUSE - " assert {:valid_deref} $sle.ref.bool($add.ref(p, size), " - "$add.ref($base(p), $Size[$base(p)]));\n" -#else - " assert {:valid_deref} $sle.ref.bool($add.ref(p, size), " - "$add.ref($base(p), $Size($base(p))));\n" -#endif - "}\n"); - - D("function $base(ref) returns (ref);"); - D("var $allocatedCounter: int;\n"); - - D("procedure $malloc(n: ref) returns (p: ref)\n" - "modifies $allocatedCounter;\n" - "{\n" - " call corral_atomic_begin();\n" - " if ($ne.ref.bool(n, $0.ref)) {\n" - " $allocatedCounter := $allocatedCounter + 1;\n" - " }\n" - " call p := $$alloc(n);\n" - " call corral_atomic_end();\n" - "}\n"); - -#if MEMORY_MODEL_NO_REUSE_IMPLS - D("var $Alloc: [ref] bool;"); - D("function $Size(ref) returns (ref);"); - D("var $CurrAddr:ref;\n"); - - // LLVM does not allocated globals explicitly. Hence, we do it in our prelude - // before the program starts using the $galloc procedure. - D("procedure $galloc(base_addr: ref, size: ref)\n" - "{\n" - " assume $Size(base_addr) == size;\n" - " assume (forall addr: ref :: {$base(addr)} $sle.ref.bool(base_addr, " - "addr) && $slt.ref.bool(addr, $add.ref(base_addr, size)) ==> $base(addr) " - "== base_addr);\n" - " $Alloc[base_addr] := true;\n" - "}\n"); - - D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref)\n" - "modifies $Alloc, $CurrAddr;\n" - "{\n" - " assume $sle.ref.bool($0.ref, n);\n" - " if ($slt.ref.bool($0.ref, n)) {\n" - " p := $CurrAddr;\n" - " havoc $CurrAddr;\n" - " assume $sge.ref.bool($sub.ref($CurrAddr, n), p);\n" - " assume $sgt.ref.bool($CurrAddr, $0.ref) && $slt.ref.bool($CurrAddr, " - "$MALLOC_TOP);\n" - " assume $Size(p) == n;\n" - " assume (forall q: ref :: {$base(q)} $sle.ref.bool(p, q) && " - "$slt.ref.bool(q, $add.ref(p, n)) ==> $base(q) == p);\n" - " $Alloc[p] := true;\n" - " } else {\n" - " p := $0.ref;\n" - " }\n" - "}\n"); - - D("procedure $free(p: ref)\n" - "modifies $Alloc, $allocatedCounter;\n" - "{\n" - " call corral_atomic_begin();\n" - " if ($ne.ref.bool(p, $0.ref)) {\n" - " assert {:valid_free} $eq.ref.bool($base(p), p);\n" - " assert {:valid_free} $Alloc[p];\n" - " assert {:valid_free} $slt.ref.bool($0.ref, p);\n" - " $Alloc[p] := false;\n" - " $allocatedCounter := $allocatedCounter - 1;\n" - " }\n" - " call corral_atomic_end();\n" - "}\n"); - -#elif MEMORY_MODEL_REUSE // can reuse previously-allocated and freed addresses - D("var $Alloc: [ref] bool;"); - D("var $Size: [ref] ref;\n"); - - // LLVM does not allocated globals explicitly. Hence, we do it in our prelude - // before the program starts using the $galloc procedure. - D("procedure $galloc(base_addr: ref, size: ref);\n" - "modifies $Alloc, $Size;\n" - "ensures $Size[base_addr] == size;\n" - "ensures (forall addr: ref :: {$base(addr)} $sle.ref.bool(base_addr, addr) " - "&& $slt.ref.bool(addr, $add.ref(base_addr, size)) ==> $base(addr) == " - "base_addr);\n" - "ensures $Alloc[base_addr];\n" - "ensures (forall q: ref :: {$Size[q]} q != base_addr ==> $Size[q] == " - "old($Size[q]));\n" - "ensures (forall q: ref :: {$Alloc[q]} q != base_addr ==> $Alloc[q] == " - "old($Alloc[q]));\n"); - - D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref);\n" - "modifies $Alloc, $Size;\n" - "ensures $sle.ref.bool($0.ref, n);\n" - "ensures $slt.ref.bool($0.ref, n) ==> $slt.ref.bool($0.ref, p) && " - "$slt.ref.bool(p, $sub.ref($MALLOC_TOP, n));\n" - "ensures $eq.ref.bool(n, $0.ref) ==> p == $0.ref;\n" - "ensures !old($Alloc[p]);\n" - "ensures (forall q: ref :: old($Alloc[q]) ==> ($slt.ref.bool($add.ref(p, " - "n), q) || $slt.ref.bool($add.ref(q, $Size[q]), p)));\n" - "ensures $Alloc[p];\n" - "ensures $Size[p] == n;\n" - "ensures (forall q: ref :: {$Size[q]} q != p ==> $Size[q] == " - "old($Size[q]));\n" - "ensures (forall q: ref :: {$Alloc[q]} q != p ==> $Alloc[q] == " - "old($Alloc[q]));\n" - "ensures (forall q: ref :: {$base(q)} $sle.ref.bool(p, q) && " - "$slt.ref.bool(q, $add.ref(p, n)) ==> $base(q) == p);\n"); - - D("procedure $free(p: ref);\n" - "modifies $Alloc, $allocatedCounter;\n" - "requires $eq.ref.bool(p, $0.ref) || ($eq.ref.bool($base(p), p) && " - "$Alloc[p]);\n" - "requires $slt.ref.bool($0.ref, p);\n" - "ensures $ne.ref.bool(p, $0.ref) ==> !$Alloc[p];\n" - "ensures $ne.ref.bool(p, $0.ref) ==> (forall q: ref :: {$Alloc[q]} q != p " - "==> $Alloc[q] == old($Alloc[q]));\n" - "ensures $ne.ref.bool(p, $0.ref) ==> $allocatedCounter == " - "old($allocatedCounter) - 1;\n"); - -#else // NO_REUSE does not reuse previously-allocated addresses - D("var $Alloc: [ref] bool;"); - D("function $Size(ref) returns (ref);"); - D("var $CurrAddr:ref;\n"); - - // LLVM does not allocated globals explicitly. Hence, we do it in our prelude - // before the program starts using the $galloc procedure. - D("procedure $galloc(base_addr: ref, size: ref);\n" - "modifies $Alloc;\n" - "ensures $Size(base_addr) == size;\n" - "ensures (forall addr: ref :: {$base(addr)} $sle.ref.bool(base_addr, addr) " - "&& $slt.ref.bool(addr, $add.ref(base_addr, size)) ==> $base(addr) == " - "base_addr);\n" - "ensures $Alloc[base_addr];\n" - "ensures (forall q: ref :: {$Alloc[q]} q != base_addr ==> $Alloc[q] == " - "old($Alloc[q]));\n"); - - D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref);\n" - "modifies $Alloc, $CurrAddr;\n" - "ensures $sle.ref.bool($0.ref, n);\n" - "ensures $slt.ref.bool($0.ref, n) ==> $sge.ref.bool($sub.ref($CurrAddr, " - "n), old($CurrAddr)) && p == old($CurrAddr);\n" - "ensures $sgt.ref.bool($CurrAddr, $0.ref) && $slt.ref.bool($CurrAddr, " - "$MALLOC_TOP);\n" - "ensures $slt.ref.bool($0.ref, n) ==> $Size(p) == n;\n" - "ensures $slt.ref.bool($0.ref, n) ==> (forall q: ref :: {$base(q)} " - "$sle.ref.bool(p, q) && $slt.ref.bool(q, $add.ref(p, n)) ==> $base(q) == " - "p);\n" - "ensures $slt.ref.bool($0.ref, n) ==> $Alloc[p];\n" - "ensures $eq.ref.bool(n, $0.ref) ==> old($CurrAddr) == $CurrAddr && p == " - "$0.ref;\n" - "ensures $eq.ref.bool(n, $0.ref)==> $Alloc[p] == old($Alloc)[p];\n" - "ensures (forall q: ref :: {$Alloc[q]} q != p ==> $Alloc[q] == " - "old($Alloc[q]));\n"); - - D("procedure $free(p: ref);\n" - "modifies $Alloc, $allocatedCounter;\n" - "requires $eq.ref.bool(p, $0.ref) || ($eq.ref.bool($base(p), p) && " - "$Alloc[p]);\n" - "requires $slt.ref.bool($0.ref, p);\n" - "ensures $ne.ref.bool(p, $0.ref) ==> !$Alloc[p];\n" - "ensures $ne.ref.bool(p, $0.ref) ==> (forall q: ref :: {$Alloc[q]} q != p " - "==> $Alloc[q] == old($Alloc[q]));\n" - "ensures $ne.ref.bool(p, $0.ref) ==> $allocatedCounter == " - "old($allocatedCounter) - 1;\n"); -#endif - -#else - D("procedure $malloc(n: ref) returns (p: ref)\n" - "{\n" - " call corral_atomic_begin();\n" - " call p := $$alloc(n);\n" - " call corral_atomic_end();\n" - "}\n"); - -#if MEMORY_MODEL_NO_REUSE_IMPLS - D("var $CurrAddr:ref;\n"); - - D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref)\n" - "modifies $CurrAddr;\n" - "{\n" - " assume $sge.ref.bool(n, $0.ref);\n" - " if ($sgt.ref.bool(n, $0.ref)) {\n" - " p := $CurrAddr;\n" - " havoc $CurrAddr;\n" - " assume $sge.ref.bool($sub.ref($CurrAddr, n), p);\n" - " assume $sgt.ref.bool($CurrAddr, $0.ref) && $slt.ref.bool($CurrAddr, " - "$MALLOC_TOP);\n" - " } else {\n" - " p := $0.ref;\n" - " }\n" - "}\n"); - - D("procedure $free(p: ref);\n"); - -#elif MEMORY_MODEL_REUSE // can reuse previously-allocated and freed addresses - D("var $Alloc: [ref] bool;"); - D("var $Size: [ref] ref;\n"); - - D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref);\n" - "modifies $Alloc, $Size;\n" - "ensures $sle.ref.bool($0.ref, n);\n" - "ensures $slt.ref.bool($0.ref, n) ==> $slt.ref.bool($0.ref, p) && " - "$slt.ref.bool(p, $sub.ref($MALLOC_TOP, n));\n" - "ensures $eq.ref.bool(n, $0.ref) ==> p == $0.ref;\n" - "ensures !old($Alloc[p]);\n" - "ensures (forall q: ref :: old($Alloc[q]) ==> ($slt.ref.bool($add.ref(p, " - "n), q) || $slt.ref.bool($add.ref(q, $Size[q]), p)));\n" - "ensures $Alloc[p];\n" - "ensures $Size[p] == n;\n" - "ensures (forall q: ref :: {$Size[q]} q != p ==> $Size[q] == " - "old($Size[q]));\n" - "ensures (forall q: ref :: {$Alloc[q]} q != p ==> $Alloc[q] == " - "old($Alloc[q]));\n"); - - D("procedure $free(p: ref);\n" - "modifies $Alloc;\n" - "ensures !$Alloc[p];\n" - "ensures (forall q: ref :: {$Alloc[q]} q != p ==> $Alloc[q] == " - "old($Alloc[q]));\n"); - -#else // NO_REUSE does not reuse previously-allocated addresses - D("var $CurrAddr:ref;\n"); - - D("procedure {:inline 1} $$alloc(n: ref) returns (p: ref);\n" - "modifies $CurrAddr;\n" - "ensures $sle.ref.bool($0.ref, n);\n" - "ensures $slt.ref.bool($0.ref, n) ==> $sge.ref.bool($sub.ref($CurrAddr, " - "n), old($CurrAddr)) && p == old($CurrAddr);\n" - "ensures $sgt.ref.bool($CurrAddr, $0.ref) && $slt.ref.bool($CurrAddr, " - "$MALLOC_TOP);\n" - "ensures $eq.ref.bool(n, $0.ref) ==> old($CurrAddr) == $CurrAddr && p == " - "$0.ref;\n"); - - D("procedure $free(p: ref);\n"); -#endif -#endif - -#undef D -} - -#if MEMORY_SAFETY -void __SMACK_check_memory_leak(void) { - __SMACK_code("assert {:valid_memtrack} $allocatedCounter == 0;"); -} -#endif - -void __SMACK_init_func_memory_model(void) { -#if MEMORY_MODEL_NO_REUSE || MEMORY_MODEL_NO_REUSE_IMPLS - __SMACK_code("$CurrAddr := $1024.ref;"); -#endif -#if MEMORY_SAFETY - __SMACK_code("$allocatedCounter := 0;"); -#endif -} - -void __VERIFIER_atomic_begin() { __SMACK_code("call corral_atomic_begin();"); } - -void __VERIFIER_atomic_end() { __SMACK_code("call corral_atomic_end();"); } diff --git a/share/smack/lib/smack/src/smack.h b/share/smack/lib/smack/src/smack.h deleted file mode 100644 index 19f755c50..000000000 --- a/share/smack/lib/smack/src/smack.h +++ /dev/null @@ -1,178 +0,0 @@ -// -// This file is distributed under the MIT License. See LICENSE for details. -// -#ifndef SMACK_H_ -#define SMACK_H_ -#include - -/** - * The SMACK "prelude" declarations - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef SVCOMP -// Apprently needed by SVCOMP benchmarks -#define __inline -#define __builtin_expect __builtinx_expect -#define __builtin_memcpy __builtinx_memcpy -#define __builtin_va_start __builtinx_va_start -#define __builtin_object_size __builtinx_object_size - -// For handling of va_start macro -void __builtinx_va_start(char *, char *); -#endif - -void __SMACK_code(const char *fmt, ...); -void __SMACK_mod(const char *fmt, ...); -void __SMACK_decl(const char *fmt, ...); -void __SMACK_top_decl(const char *fmt, ...); - -typedef struct smack_value { - void *dummy; -} * smack_value_t; -smack_value_t __SMACK_value(); -smack_value_t __SMACK_values(void *ary, unsigned count); -smack_value_t __SMACK_return_value(void); - -// Sugar for __SMACK_init_func_XXX() -#define __SMACK_INIT(x) void __SMACK_init_func_##x() - -#if MEMORY_SAFETY -// Inserts memory access checks in form of assert to check null pointer access -// and buffer overflow errors -void __SMACK_check_memory_safety(void *, void *) __attribute__((const)); -void __SMACK_check_memory_leak(void); -#endif - -// We need this to enforce that assert/assume are function calls -// with an integer argument (DSA gets confused otherwise) -__attribute__((always_inline)) void __SMACK_dummy(int v); - -void __VERIFIER_assume(int); -#ifndef CUSTOM_VERIFIER_ASSERT -void __VERIFIER_assert(int); -#endif - -#ifndef AVOID_NAME_CONFLICTS -#define assert(EX) \ - do { \ - if (!(EX)) \ - __VERIFIER_assert(0); \ - } while (0) -#define assume(EX) \ - do { \ - if (!(EX)) \ - __VERIFIER_assume(0); \ - } while (0) -#endif - -#define S4(a, b, c, d) a b c d -#define S3(a, b, c) a b c -#define S2(a, b) a b -#define S1(a) a -#define U4(a, b, c, d) a##_##b##_##c##_##d -#define U3(a, b, c) a##_##b##_##c -#define U2(a, b) a##_##b -#define U1(a) a - -#define TY(_1, _2, _3, _4, A, ...) A - -#define S(...) TY(__VA_ARGS__, S4, S3, S2, S1)(__VA_ARGS__) -#define U(...) TY(__VA_ARGS__, U4, U3, U2, U1)(__VA_ARGS__) - -#define NONDET_DECL(P, ty...) S(ty) U(P, U(ty))(void) - -void *__VERIFIER_nondet(void); -NONDET_DECL(__SMACK_nondet, char); -NONDET_DECL(__SMACK_nondet, signed, char); -NONDET_DECL(__SMACK_nondet, unsigned, char); -NONDET_DECL(__SMACK_nondet, short); -NONDET_DECL(__SMACK_nondet, short, int); -NONDET_DECL(__SMACK_nondet, signed, short); -NONDET_DECL(__SMACK_nondet, signed, short, int); -NONDET_DECL(__SMACK_nondet, unsigned, short); -NONDET_DECL(__SMACK_nondet, unsigned, short, int); -NONDET_DECL(__SMACK_nondet, int); -NONDET_DECL(__SMACK_nondet, signed, int); -NONDET_DECL(__SMACK_nondet, unsigned); -NONDET_DECL(__SMACK_nondet, unsigned, int); -NONDET_DECL(__SMACK_nondet, long); -NONDET_DECL(__SMACK_nondet, long, int); -NONDET_DECL(__SMACK_nondet, signed, long); -NONDET_DECL(__SMACK_nondet, signed, long, int); -NONDET_DECL(__SMACK_nondet, unsigned, long); -NONDET_DECL(__SMACK_nondet, unsigned, long, int); -NONDET_DECL(__SMACK_nondet, long, long); -NONDET_DECL(__SMACK_nondet, long, long, int); -NONDET_DECL(__SMACK_nondet, signed, long, long); -NONDET_DECL(__SMACK_nondet, signed, long, long, int); -NONDET_DECL(__SMACK_nondet, unsigned, long, long); -NONDET_DECL(__SMACK_nondet, unsigned, long, long, int); -NONDET_DECL(__VERIFIER_nondet, char); -NONDET_DECL(__VERIFIER_nondet, signed, char); -NONDET_DECL(__VERIFIER_nondet, unsigned, char); -NONDET_DECL(__VERIFIER_nondet, short); -NONDET_DECL(__VERIFIER_nondet, short, int); -NONDET_DECL(__VERIFIER_nondet, signed, short); -NONDET_DECL(__VERIFIER_nondet, signed, short, int); -NONDET_DECL(__VERIFIER_nondet, unsigned, short); -NONDET_DECL(__VERIFIER_nondet, unsigned, short, int); -NONDET_DECL(__VERIFIER_nondet, int); -NONDET_DECL(__VERIFIER_nondet, signed, int); -NONDET_DECL(__VERIFIER_nondet, unsigned); -NONDET_DECL(__VERIFIER_nondet, unsigned, int); -NONDET_DECL(__VERIFIER_nondet, long); -NONDET_DECL(__VERIFIER_nondet, long, int); -NONDET_DECL(__VERIFIER_nondet, signed, long); -NONDET_DECL(__VERIFIER_nondet, signed, long, int); -NONDET_DECL(__VERIFIER_nondet, unsigned, long); -NONDET_DECL(__VERIFIER_nondet, unsigned, long, int); -NONDET_DECL(__VERIFIER_nondet, long, long); -NONDET_DECL(__VERIFIER_nondet, long, long, int); -NONDET_DECL(__VERIFIER_nondet, signed, long, long); -NONDET_DECL(__VERIFIER_nondet, signed, long, long, int); -NONDET_DECL(__VERIFIER_nondet, unsigned, long, long); -NONDET_DECL(__VERIFIER_nondet, unsigned, long, long, int); -NONDET_DECL(__VERIFIER_nondet, float); -NONDET_DECL(__VERIFIER_nondet, double); -NONDET_DECL(__VERIFIER_nondet, long, double); - -#undef S1 -#undef S2 -#undef S3 -#undef S4 -#undef U1 -#undef U2 -#undef U3 -#undef U4 -#undef TY -#undef S -#undef U -#undef NONDET_DECL - -// Used in SVCOMP benchmarks -#ifdef __cplusplus -bool __VERIFIER_nondet_bool(void); -#else -_Bool __VERIFIER_nondet_bool(void); -#endif -unsigned char __VERIFIER_nondet_uchar(void); -unsigned short __VERIFIER_nondet_ushort(void); -unsigned __VERIFIER_nondet_uint(void); -unsigned long __VERIFIER_nondet_ulong(void); -void *__VERIFIER_nondet_pointer(void); - -void __SMACK_decls(void); - -// Concurrency helper functions -void __VERIFIER_atomic_begin(); -void __VERIFIER_atomic_end(); - -#ifdef __cplusplus -} -#endif - -#endif /*SMACK_H_*/ From da8c95b74a10ed494d78e3e33d1f27fdfe2d4555 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 21 Oct 2020 18:48:23 -0600 Subject: [PATCH 049/109] Remove extra smack.rs --- CMakeLists.txt | 6 + share/smack/lib/smack/src/lib.rs | 551 ------------------------------- 2 files changed, 6 insertions(+), 551 deletions(-) delete mode 100644 share/smack/lib/smack/src/lib.rs diff --git a/CMakeLists.txt b/CMakeLists.txt index eca095bc6..20b81f9c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,3 +219,9 @@ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/share/smack/lib/smack.c DESTINATION share/smack/smack/src ) + +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/share/smack/lib/smack.rs + DESTINATION share/smack/smack/src + RENAME lib.rs +) diff --git a/share/smack/lib/smack/src/lib.rs b/share/smack/lib/smack/src/lib.rs deleted file mode 100644 index 21ec33bc3..000000000 --- a/share/smack/lib/smack/src/lib.rs +++ /dev/null @@ -1,551 +0,0 @@ -#![crate_type = "staticlib"] - -#[cfg(verifier = "smack")] -extern "C" { - pub fn __VERIFIER_assert(x: i32); - pub fn __VERIFIER_assume(x: i32); - pub fn __VERIFIER_nondet_signed_char() -> i8; - pub fn __VERIFIER_nondet_unsigned_char() -> u8; - pub fn __VERIFIER_nondet_signed_short() -> i16; - pub fn __VERIFIER_nondet_unsigned_short() -> u16; - pub fn __VERIFIER_nondet_signed_int() -> i32; - pub fn __VERIFIER_nondet_unsigned_int() -> u32; - pub fn __VERIFIER_nondet_signed_long_long() -> i64; - pub fn __VERIFIER_nondet_unsigned_long_long() -> u64; - pub fn malloc(size: usize) -> *mut u8; - pub fn __VERIFIER_memcpy(dest: *mut u8, src: *mut u8, count: usize) -> *mut u8; - pub fn free(ptr: *mut u8); -} - -#[macro_export] -macro_rules! verifier_assert { - ( $cond:expr ) => { - unsafe { - __VERIFIER_assert($cond as i32); - }; - }; -} - -#[cfg(verifier = "smack")] -#[macro_export] -macro_rules! print { - ($fmt:expr) => (); - ($fmt:expr, $($arg:expr),*) => ( $($arg);* ) -} - -#[cfg(verifier = "smack")] -#[macro_export] -macro_rules! println { - ($($arg:tt)*) => ( print!($($arg)*) ) -} - -#[cfg(verifier = "smack")] -#[macro_export] -macro_rules! eprint { - ($($arg:tt)*) => ( print!($($arg)*) ) -} - -#[cfg(verifier = "smack")] -#[macro_export] -macro_rules! eprintln { - ($($arg:tt)*) => ( print!($($arg)*) ) -} - -#[cfg(verifier = "smack")] -#[macro_export] -macro_rules! assert { - ( $cond:expr ) => { - verifier_assert!($cond); - }; -} - -#[cfg(verifier = "smack")] -#[macro_export] -macro_rules! assert_eq { - ( $lhs:expr, $rhs:expr ) => { - smack::assert!($lhs == $rhs); - }; -} - -#[cfg(verifier = "smack")] -#[macro_export] -macro_rules! assert_neq { - ( $lhs:expr, $rhs:expr ) => { - smack::assert!($lhs != $rhs); - }; -} - -#[macro_export] -macro_rules! verifier_assume { - ( $cond:expr ) => { - #[cfg(verifier = "smack")] - unsafe { - __VERIFIER_assume($cond as i32); - } - - #[cfg(not(verifier = "smack"))] - (); - }; -} - -#[macro_export] -macro_rules! assume { - ( $cond:expr ) => { - verifier_assume!($cond); - }; -} - -#[macro_export] -macro_rules! verifier_nondet { - ($e:expr) => - ( - #[cfg(verifier = "smack")] - $e.verifier_nondet() - - #[cfg(not(verifier = "smack"))] - $e - ) -} - -pub trait VerifierNonDet { - fn verifier_nondet(self) -> Self; -} - -#[macro_export] -macro_rules! make_verifier_nondet { - ($typ:ident, $nondet:ident) => { - impl VerifierNonDet for $typ { - #[cfg(verifier = "smack")] - fn verifier_nondet(self) -> Self { - unsafe { $nondet() as Self } - } - - #[cfg(not(verifier = "smack"))] - fn verifier_nondet(self) -> Self { - self - } - } - }; -} - -/* Instantiate nondet for all integer types. */ -make_verifier_nondet!(i8, __VERIFIER_nondet_signed_char); -make_verifier_nondet!(u8, __VERIFIER_nondet_unsigned_char); -make_verifier_nondet!(i16, __VERIFIER_nondet_signed_short); -make_verifier_nondet!(u16, __VERIFIER_nondet_unsigned_short); -make_verifier_nondet!(i32, __VERIFIER_nondet_signed_int); -make_verifier_nondet!(u32, __VERIFIER_nondet_unsigned_int); -make_verifier_nondet!(i64, __VERIFIER_nondet_signed_long_long); -make_verifier_nondet!(u64, __VERIFIER_nondet_unsigned_long_long); -make_verifier_nondet!(isize, __VERIFIER_nondet_signed_long_long); -make_verifier_nondet!(usize, __VERIFIER_nondet_unsigned_long_long); - -#[cfg(not(verifier = "smack"))] -#[cfg(feature = "std")] -#[allow(dead_code)] -use std::Vec; -/* Vector class. -Based on https://doc.rust-lang.org/nomicon/vec-final.html */ -#[cfg(verifier = "smack")] -#[allow(dead_code)] -fn sized_realloc(orig_ptr: *mut u8, orig_size: usize, new_size: usize) -> *mut u8 { - unsafe { - let result: *mut u8 = malloc(new_size); - __VERIFIER_memcpy(result, orig_ptr, orig_size); - result - } -} - -#[cfg(verifier = "smack")] -use std::mem; -#[cfg(verifier = "smack")] -use std::ops::{Deref, DerefMut}; -#[cfg(verifier = "smack")] -use std::ptr::{self, null}; - -#[cfg(verifier = "smack")] -#[allow(dead_code)] -pub struct PhantomData { - _place_holder: *const T, - _padding: u64, -} - -#[cfg(verifier = "smack")] -impl Default for PhantomData { - fn default() -> Self { - PhantomData:: { - _place_holder: ptr::null(), - _padding: 0, - } - } -} - -#[cfg(verifier = "smack")] -#[allow(dead_code)] -struct Unique { - // _marker: PhantomData, // For the drop checker - ptr: *const T, // *const for variance - _marker: u64, -} - -#[cfg(verifier = "smack")] -impl Unique { - pub fn new(ptr: *mut T) -> Self { - Unique { - ptr: ptr, - _marker: Default::default(), - } - } - - pub fn as_ptr(&self) -> *mut T { - self.ptr as *mut T - } -} - -#[cfg(verifier = "smack")] -#[allow(dead_code)] -struct RawVec { - ptr: Unique, - cap: usize, -} - -#[cfg(verifier = "smack")] -#[allow(dead_code)] -impl RawVec { - fn new() -> Self { - let elem_size = mem::size_of::(); - let cap = 32; - let ptr = unsafe { Unique::new(malloc(cap * elem_size) as *mut T) }; - RawVec { ptr: ptr, cap: cap } - } - - fn new_with_capacity(cap: usize) -> Self { - let elem_size = mem::size_of::(); - let ptr = unsafe { Unique::new(malloc(cap * elem_size) as *mut T) }; - RawVec { ptr: ptr, cap: cap } - } - - fn grow(&mut self) { - let elem_size = mem::size_of::(); - let new_cap = 2 * self.cap; - let ptr = sized_realloc( - self.ptr.as_ptr() as *mut _, - self.cap * elem_size, - new_cap * elem_size, - ); - - self.ptr = Unique::new(ptr as *mut _); - self.cap = new_cap; - } -} - -#[cfg(verifier = "smack")] -impl Drop for RawVec { - fn drop(&mut self) { - unsafe { free(self.ptr.ptr as *mut _) }; - } -} - -#[cfg(verifier = "smack")] -pub struct Vec { - buf: RawVec, - len: usize, -} - -#[cfg(verifier = "smack")] -impl Vec { - fn ptr(&self) -> *mut T { - self.buf.ptr.as_ptr() - } - - #[allow(dead_code)] - fn cap(&self) -> usize { - self.buf.cap - } - - pub fn new() -> Self { - Vec { - buf: RawVec::new(), - len: 0, - } - } - - #[allow(dead_code)] - pub fn with_capacity(cap: usize) -> Self { - Vec { - buf: RawVec::new_with_capacity(cap), - len: 0, - } - } - - #[allow(dead_code)] - pub fn push(&mut self, elem: T) { - if self.len == self.cap() { - self.buf.grow(); - } - - unsafe { - ptr::write(self.ptr().offset(self.len as isize), elem); - } - - self.len += 1; - } - - #[allow(dead_code)] - pub fn pop(&mut self) -> Option { - if self.len == 0 { - None - } else { - self.len -= 1; - unsafe { Some(ptr::read(self.ptr().offset(self.len as isize))) } - } - } - - #[allow(dead_code)] - pub fn append(&mut self, other: &mut Vec) { - let mut i: usize = 0; - let olen = other.len(); - let mut drain = Vec::new(); - while i < olen { - drain.push(other.pop().unwrap()); - i += 1; - } - // Empty other - i = 0; - while i < olen { - self.push(drain.pop().unwrap()); - i += 1; - } - } - - #[allow(dead_code)] - pub fn insert(&mut self, index: usize, elem: T) { - assert!(index <= self.len); - if self.cap() == self.len { - self.buf.grow(); - } - - unsafe { - if index < self.len { - ptr::copy( - self.ptr().offset(index as isize), - self.ptr().offset(index as isize + 1), - self.len - index, - ); - } - ptr::write(self.ptr().offset(index as isize), elem); - self.len += 1; - } - } - - #[allow(dead_code)] - pub fn remove(&mut self, index: usize) -> T { - assert!(index < self.len); - unsafe { - self.len -= 1; - let result = ptr::read(self.ptr().offset(index as isize)); - ptr::copy( - self.ptr().offset(index as isize + 1), - self.ptr().offset(index as isize), - self.len - index, - ); - result - } - } - - #[allow(dead_code)] - pub fn into_iter(self) -> IntoIter { - unsafe { - let iter = RawValIter::new(&self); - let buf = ptr::read(&self.buf); - mem::forget(self); - - IntoIter { - iter: iter, - _buf: buf, - } - } - } - #[allow(dead_code)] - pub fn len(&self) -> usize { - self.len - } -} - -#[cfg(verifier = "smack")] -impl Default for Vec { - fn default() -> Self { - Vec::new() - } -} - -#[cfg(verifier = "smack")] -impl Drop for Vec { - fn drop(&mut self) { - while let Some(_) = self.pop() {} - // allocation is handled by RawVec - } -} - -#[cfg(verifier = "smack")] -impl Deref for Vec { - type Target = [T]; - fn deref(&self) -> &[T] { - unsafe { ::std::slice::from_raw_parts(self.buf.ptr.ptr, self.len) } - } -} - -#[cfg(verifier = "smack")] -impl DerefMut for Vec { - fn deref_mut(&mut self) -> &mut [T] { - unsafe { ::std::slice::from_raw_parts_mut(self.buf.ptr.ptr as *mut T, self.len) } - } -} - -#[cfg(verifier = "smack")] -struct RawValIter { - start: *const T, - end: *const T, -} - -#[cfg(verifier = "smack")] -impl RawValIter { - unsafe fn new(slice: &[T]) -> Self { - RawValIter { - start: slice.as_ptr(), - end: if mem::size_of::() == 0 { - ((slice.as_ptr() as usize) + slice.len()) as *const _ - } else if slice.len() == 0 { - slice.as_ptr() - } else { - slice.as_ptr().offset(slice.len() as isize) - }, - } - } -} - -#[cfg(verifier = "smack")] -impl Iterator for RawValIter { - type Item = T; - fn next(&mut self) -> Option { - if self.start == self.end { - None - } else { - unsafe { - let result = ptr::read(self.start); - self.start = if mem::size_of::() == 0 { - (self.start as usize + 1) as *const _ - } else { - self.start.offset(1) - }; - Some(result) - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let elem_size = mem::size_of::(); - let len = - (self.end as usize - self.start as usize) / if elem_size == 0 { 1 } else { elem_size }; - (len, Some(len)) - } -} - -#[cfg(verifier = "smack")] -impl DoubleEndedIterator for RawValIter { - fn next_back(&mut self) -> Option { - if self.start == self.end { - None - } else { - unsafe { - self.end = if mem::size_of::() == 0 { - (self.end as usize - 1) as *const _ - } else { - self.end.offset(-1) - }; - Some(ptr::read(self.end)) - } - } - } -} - -#[cfg(verifier = "smack")] -pub struct IntoIter { - _buf: RawVec, // we don't actually care about this. Just need it to live. - iter: RawValIter, -} - -#[cfg(verifier = "smack")] -impl Iterator for IntoIter { - type Item = T; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[cfg(verifier = "smack")] -impl DoubleEndedIterator for IntoIter { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } -} - -#[cfg(verifier = "smack")] -impl Drop for IntoIter { - fn drop(&mut self) { - for _ in &mut *self {} - } -} - -#[cfg(verifier = "smack")] -#[macro_export] -macro_rules! vec { - ( $val:expr ; $count:expr ) => - ({ - let mut result = Vec::new(); - let mut i = 0u64; - while i < $count { - result.push($val); - i += 1; - } - result - }); - ( $( $xs:expr ),* ) => { - { - let mut result = Vec::new(); - $( - result.push($xs); - )* - result - } - }; -} - -#[cfg(verifier = "smack")] -#[allow(dead_code)] -pub struct Box { - ptr: Unique, -} - -#[cfg(verifier = "smack")] -#[allow(dead_code)] -impl Box { - pub fn new(item: T) -> Box { - let elem_size = mem::size_of::(); - let ptr = unsafe { Unique::new(malloc(elem_size) as *mut T) }; - unsafe { ptr::write(ptr.as_ptr().offset(0), item) }; - Box { ptr: ptr } - } -} - -#[cfg(verifier = "smack")] -#[allow(dead_code)] -impl Deref for Box { - type Target = T; - fn deref(&self) -> &Self::Target { - unsafe { mem::transmute::<*mut T, &T>(self.ptr.as_ptr()) } - } -} From 767ab6746d2c0b6412225cb52bc5492ee1214bfd Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Fri, 23 Oct 2020 18:02:42 -0600 Subject: [PATCH 050/109] Clang format --- share/smack/include/smack.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/share/smack/include/smack.h b/share/smack/include/smack.h index 4d2c40064..60527f66a 100644 --- a/share/smack/include/smack.h +++ b/share/smack/include/smack.h @@ -84,10 +84,11 @@ void __VERIFIER_assert(int); #define U(...) TY(__VA_ARGS__, U4, U3, U2, U1)(__VA_ARGS__) #define NONDET_DECL(P, ty...) S(ty) U(P, U(ty))(void) -#define EMPTY_NONDET_DEFN(P, ty...) S(ty) U(P, U(ty))(void) { \ - ty x; \ - return x; \ -} +#define EMPTY_NONDET_DEFN(P, ty...) \ + S(ty) U(P, U(ty))(void) { \ + ty x; \ + return x; \ + } void *__VERIFIER_nondet(void); NONDET_DECL(__SMACK_nondet, char); From 356618f286d5fc47029d85976ad0f129a3b2d344 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sun, 25 Oct 2020 11:22:57 -0600 Subject: [PATCH 051/109] Implemented modeling of memcmp I implemented it using a loop, which then has to be unrolled an appropriate amount of times. This could be improved if we want to use quantifiers, but I think this should be good for now. Closes #629 --- share/smack/include/string.h | 1 + share/smack/lib/string.c | 21 +++++++++++++++++++++ test/c/strings/test_memcmp.c | 20 ++++++++++++++++++++ test/c/strings/test_memcmp_fail.c | 17 +++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 test/c/strings/test_memcmp.c create mode 100644 test/c/strings/test_memcmp_fail.c diff --git a/share/smack/include/string.h b/share/smack/include/string.h index 8c7c6c7c3..d1f53980f 100644 --- a/share/smack/include/string.h +++ b/share/smack/include/string.h @@ -7,6 +7,7 @@ #include void *memcpy(void *str1, const void *str2, size_t n); +int memcmp(const void *str1, const void *str2, size_t n); void *memset(void *str, int c, size_t n); char *strcpy(char *dest, const char *src); diff --git a/share/smack/lib/string.c b/share/smack/lib/string.c index 8530aa86f..e6c0077aa 100644 --- a/share/smack/lib/string.c +++ b/share/smack/lib/string.c @@ -5,6 +5,27 @@ #include #include +int memcmp(const void *str1, const void *str2, size_t n) { + const unsigned char *s1 = (const unsigned char *)str1; + const unsigned char *s2 = (const unsigned char *)str2; + + while (n--) { + if (*s1 != *s2) { + int result = __VERIFIER_nondet_int(); + if (*s1 < *s2) { + __VERIFIER_assume(result < 0); + } else { + __VERIFIER_assume(result > 0); + } + return result; + } + s1++; + s2++; + } + + return 0; +} + char *strcpy(char *dest, const char *src) { char *save = dest; while ((*dest++ = *src++)) diff --git a/test/c/strings/test_memcmp.c b/test/c/strings/test_memcmp.c new file mode 100644 index 000000000..f548437f7 --- /dev/null +++ b/test/c/strings/test_memcmp.c @@ -0,0 +1,20 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + char word1[] = "Test memcmp"; + char word2[] = "Test memcmp"; + char word3[] = "Test memcpy"; + int result; + + result = memcmp(word1, word2, 11); + assert(result == 0); + result = memcmp(word1, word3, 11); + assert(result < 0); + result = memcmp(word1, word3, 8); + assert(result == 0); + + return 0; +} diff --git a/test/c/strings/test_memcmp_fail.c b/test/c/strings/test_memcmp_fail.c new file mode 100644 index 000000000..ed65f13ef --- /dev/null +++ b/test/c/strings/test_memcmp_fail.c @@ -0,0 +1,17 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + char word1[] = "Test memcmp"; + char word2[] = "Test memcpy"; + char word3[] = "Test memcmp"; + int result1, result2; + + result1 = memcmp(word1, word2, 11); + result2 = memcmp(word1, word3, 11); + assert(result1 >= 0 || result2 != 0); + + return 0; +} From 9debfdff9a1d36e73cf6306a23254baf833d4951 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sun, 25 Oct 2020 11:27:52 -0600 Subject: [PATCH 052/109] Modeling of strings must be turned on by default --- share/smack/svcomp/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 26f2b3dec..ae9408efe 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -14,15 +14,15 @@ def svcomp_frontend(input_file, args): # enable static LLVM unroll pass args.static_unroll = True + # Modeling of strings must be turned on by default + args.strings = True + if len(args.input_files) > 1: raise RuntimeError("Expected a single SVCOMP input file.") # check svcomp properties and set flags accordingly svcomp_check_property(args) - if 'memory-safety' in args.check or 'memleak' in args.check or 'integer-overflow' in args.check: - args.strings = True - name, ext = os.path.splitext(os.path.basename(args.input_files[0])) args.orig_files = list(args.input_files) From 5f2f4d04c7730271c0025f3873f6e8becd388ae6 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sun, 25 Oct 2020 20:29:26 -0600 Subject: [PATCH 053/109] Bug fix related to selecting multiple properties to check As it turns out, we have a bug in the argument parser that lead to only the past listed property in the command line to be checked. This commit fixed that and now all the properties are collected. Fixes #626 --- share/smack/top.py | 1 + 1 file changed, 1 insertion(+) diff --git a/share/smack/top.py b/share/smack/top.py index 0edb65918..53857d884 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -303,6 +303,7 @@ def arguments(): '--check', metavar='PROPERTY', nargs='+', + action='append', choices=['assertions', 'memory-safety', 'valid-deref', 'valid-free', 'memleak', 'integer-overflow', 'rust-panics'], default=['assertions'], From 78905bdb1e09dd0e78468132af59af760db2a9e7 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 26 Oct 2020 08:11:34 -0600 Subject: [PATCH 054/109] Proper handling of check command line options This commit properly implements the handling of check command line option. Closes #626 --- share/smack/frontend.py | 2 ++ share/smack/lib/smack.c | 2 +- share/smack/top.py | 8 ++++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/share/smack/frontend.py b/share/smack/frontend.py index 1479a9519..bc8839c7d 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -92,6 +92,8 @@ def default_clang_compile_command(args, lib=False): if 'integer-overflow' in args.check: cmd += (['-fsanitize=signed-integer-overflow,shift'] if not lib else ['-DSIGNED_INTEGER_OVERFLOW_CHECK']) + if not 'assertions' in args.check: + cmd += ['-DDISABLE_SMACK_ASSERTIONS'] if args.float: cmd += ['-DFLOAT_ENABLED'] if args.pthread: diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index 61c7651c0..dbe07949f 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -40,7 +40,7 @@ void __VERIFIER_assume(int x) { #ifndef CUSTOM_VERIFIER_ASSERT void __VERIFIER_assert(int x) { -#if !MEMORY_SAFETY && !SIGNED_INTEGER_OVERFLOW_CHECK +#if !DISABLE_SMACK_ASSERTIONS __SMACK_dummy(x); __SMACK_code("assert @ != $0;", x); #endif diff --git a/share/smack/top.py b/share/smack/top.py index 53857d884..e286db775 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -306,9 +306,8 @@ def arguments(): action='append', choices=['assertions', 'memory-safety', 'valid-deref', 'valid-free', 'memleak', 'integer-overflow', 'rust-panics'], - default=['assertions'], help='''select properties to check - [choices: %(choices)s; default: %(default)s] + [choices: %(choices)s; default: assertions] (note that memory-safety is the union of valid-deref, valid-free, memleak)''') @@ -447,6 +446,11 @@ def arguments(): args.bpl_file = 'a.bpl' if args.no_verify else temporary_file( 'a', '.bpl', args) + if not args.check: + args.check = {'assertions'} + else: + args.check = set([val for sublist in args.check for val in sublist]) + # TODO are we (still) using this? # with open(args.input_file, 'r') as f: # for line in f.readlines(): From 5569485c5f24f32b8fc162269ac423b5249019f2 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 26 Oct 2020 09:46:19 -0600 Subject: [PATCH 055/109] Minor fix to satisfy flang python formatting --- share/smack/frontend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/smack/frontend.py b/share/smack/frontend.py index bc8839c7d..ae2e2f647 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -92,7 +92,7 @@ def default_clang_compile_command(args, lib=False): if 'integer-overflow' in args.check: cmd += (['-fsanitize=signed-integer-overflow,shift'] if not lib else ['-DSIGNED_INTEGER_OVERFLOW_CHECK']) - if not 'assertions' in args.check: + if 'assertions' not in args.check: cmd += ['-DDISABLE_SMACK_ASSERTIONS'] if args.float: cmd += ['-DFLOAT_ENABLED'] From bee0067e2a2427fc498755324eeb2511240d36e6 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 26 Oct 2020 16:13:20 -0600 Subject: [PATCH 056/109] Fixes after merging with develop --- share/smack/frontend.py | 2 +- share/smack/top.py | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/share/smack/frontend.py b/share/smack/frontend.py index a4ad73e1a..176088912 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -94,7 +94,7 @@ def default_clang_compile_command(args, lib=False): if VProperty.INTEGER_OVERFLOW in args.check: cmd += (['-fsanitize=signed-integer-overflow,shift'] if not lib else ['-DSIGNED_INTEGER_OVERFLOW_CHECK']) - if 'assertions' not in args.check: + if VProperty.ASSERTIONS not in args.check: cmd += ['-DDISABLE_SMACK_ASSERTIONS'] if args.float: cmd += ['-DFLOAT_ENABLED'] diff --git a/share/smack/top.py b/share/smack/top.py index 5159b12c8..aecc92795 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -96,6 +96,7 @@ def __call__(self, parser, namespace, values, option_string=None): # Shaobo: shamelessly borrowed it from https://stackoverflow.com/a/55500795 class VProperty(Flag): + NONE = 0 ASSERTIONS = auto() VALID_DEREF = auto() VALID_FREE = auto() @@ -429,7 +430,7 @@ def arguments(): metavar='PROPERTY', nargs='+', choices=list(VProperty), - default=VProperty.ASSERTIONS, + default=VProperty.NONE, type=VProperty.argparse, action=PropertyAction, help='''select properties to check @@ -572,10 +573,8 @@ def arguments(): args.bpl_file = 'a.bpl' if args.no_verify else temporary_file( 'a', '.bpl', args) - if not args.check: - args.check = {'assertions'} - else: - args.check = set([val for sublist in args.check for val in sublist]) + if args.check == VProperty.NONE: + args.check = VProperty.ASSERTIONS # TODO are we (still) using this? # with open(args.input_file, 'r') as f: From 0912b41be21818125168cbd9c2dc1174dfb1dc9b Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 26 Oct 2020 17:04:06 -0600 Subject: [PATCH 057/109] Fixed svcomp scripts --- share/smack/svcomp/utils.py | 46 +++++++++++++++++++++++-------------- share/smack/top.py | 2 +- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index ae9408efe..ebf6b8d44 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -48,15 +48,18 @@ def svcomp_check_property(args): if args.svcomp_property: with open(args.svcomp_property, "r") as f: prop = f.read() + from smack.top import VProperty + from smack.top import VResult if "valid-deref" in prop: - args.check = ['memory-safety'] + args.check = VProperty.MEMORY_SAFETY elif "valid-memcleanup" in prop: - args.check = ['memleak'] + args.check = VProperty.MEMLEAK elif "overflow" in prop: - args.check = ['integer-overflow'] + args.check = VProperty.INTEGER_OVERFLOW elif not "reach_error" in prop: - print(smack.top.results(args)['unknown'][0]) - sys.exit(smack.top.results(args)['unknown'][1]) + result = VResult.UNKNOWN + print(result.message(args)) + sys.exit(result.return_code()) def force_timeout(): sys.stdout.flush() @@ -73,7 +76,12 @@ def verify_bpl_svcomp(args): """Verify the Boogie source file using SVCOMP-tuned heuristics.""" heurTrace = "\n\nHeuristics Info:\n" - if not 'memory-safety' in args.check and not 'memleak' in args.check and not 'integer-overflow' in args.check: + from smack.top import VProperty + from smack.top import VResult + + if (VProperty.MEMORY_SAFETY not in args.check + and VProperty.MEMLEAK not in args.check + and VProperty.INTEGER_OVERFLOW not in args.check): inject_assert_false(args) corral_command = ["corral"] @@ -87,7 +95,9 @@ def verify_bpl_svcomp(args): csource = f.read() corral_command += ["/k:1"] - if not ('memory-safety' in args.check or args.integer_encoding == 'bit-vector' or 'memleak' in args.check): + if not (VProperty.MEMORY_SAFETY in args.check + or args.integer_encoding == 'bit-vector' + or VProperty.MEMLEAK in args.check): if not ("dll_create" in csource or "sll_create" in csource or "changeMethaneLevel" in csource): corral_command += ["/di"] @@ -107,14 +117,14 @@ def verify_bpl_svcomp(args): verifier_output = smack.top.try_command(command, timeout=time_limit) result = smack.top.verification_result(verifier_output) - if result == 'error' or result == 'invalid-deref' or result == 'invalid-free' or result == 'invalid-memtrack' or result == 'overflow': #normal inlining + if result in VResult.ERROR: #normal inlining heurTrace += "Found a bug during normal inlining.\n" if not args.quiet: error = smack.top.error_trace(verifier_output, args) print(error) - elif result == 'timeout': #normal inlining + elif result is VResult.TIMEOUT: #normal inlining heurTrace += "Timed out during normal inlining.\n" heurTrace += "Determining result based on how far we unrolled.\n" # If we managed to unroll more than loopUnrollBar times, then return verified @@ -135,9 +145,9 @@ def verify_bpl_svcomp(args): heurTrace += "Reporting benchmark as 'verified'.\n" if not args.quiet: print((heurTrace + "\n")) - write_error_file(args, 'verified', verifier_output) - print(smack.top.results(args)['verified'][0]) - sys.exit(smack.top.results(args)['verified'][1]) + write_error_file(args, VResult.VERIFIED, verifier_output) + print(VResult.VERIFIED.message(args)) + sys.exit(VResult.VERIFIED.return_code()) else: heurTrace += "Only unrolled " + str(unrollMax) + " times.\n" heurTrace += "Insufficient unrolls to consider 'verified'. " @@ -146,21 +156,23 @@ def verify_bpl_svcomp(args): print((heurTrace + "\n")) sys.stdout.flush() force_timeout() - elif result == 'verified': #normal inlining + elif result is VResult.VERIFIED: #normal inlining heurTrace += "Normal inlining terminated and found no bugs.\n" else: #normal inlining heurTrace += "Normal inlining returned 'unknown'. See errors above.\n" if not args.quiet: print((heurTrace + "\n")) write_error_file(args, result, verifier_output) - print(smack.top.results(args)[result][0]) - sys.exit(smack.top.results(args)[result][1]) + print(result.message(args)) + sys.exit(result.return_code()) def write_error_file(args, status, verifier_output): + from smack.top import VProperty + from smack.top import VResult #return - if status == 'timeout' or status == 'unknown': + if status is VResult.VERIFIED or status is VResult.UNKNOWN: return - hasBug = (status != 'verified') + hasBug = (status is not VResult.VERIFIED) #if not hasBug: # return if args.error_file: diff --git a/share/smack/top.py b/share/smack/top.py index aecc92795..bee14e0af 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -127,7 +127,7 @@ def contains_mem_safe_props(self): def boogie_attr(self): def get_attr_from_result(x): - if x in VProperty.mem_safe_subprops(): + if x in VResult.MEMSAFETY_ERROR: return x.name.lower()[2:] else: return x.name.lower() From 4b5ee93f70571d855ab23ecf46d74b5b5541bb9f Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 26 Oct 2020 17:45:26 -0600 Subject: [PATCH 058/109] Added comments --- share/smack/top.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/share/smack/top.py b/share/smack/top.py index bee14e0af..604f4b34b 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -18,6 +18,12 @@ class VResult(Flag): + ''' + This class represents verification results. + `MEMSAFETY_ERROR` and `ERROR` do not correspond to any results. They are + used to group certain results. + ''' + VERIFIED = auto() ASSERTION_FAILURE = auto() INVALID_DEREF = auto() @@ -35,6 +41,8 @@ def __str__(self): return self.name.lower().replace('_', '-') def description(self): + '''Return the description for certain result.''' + descriptions = { VResult.ASSERTION_FAILURE: '', VResult.INVALID_DEREF: 'invalid pointer dereference', @@ -50,6 +58,8 @@ def description(self): % self) def return_code(self): + '''Return the exit code for each result.''' + return_codes = { VResult.VERIFIED: 0, VResult.ASSERTION_FAILURE: 1, @@ -68,6 +78,8 @@ def return_code(self): % self) def message(self, args): + '''Return SMACK's output for each result.''' + if self is VResult.VERIFIED: return ('SMACK found no errors' + ('' if args.modular else ' with unroll bound %s' @@ -85,10 +97,20 @@ def message(self, args): class PropertyAction(argparse.Action): + ''' + This class defines the argparse action when the arguments of the `--check` + option are consumed. + ''' + def __init__(self, option_strings, dest, **kwargs): super(PropertyAction, self).__init__(option_strings, dest, **kwargs) def __call__(self, parser, namespace, values, option_string=None): + ''' + Fold the provided arguments with bitwise or. This is equivalent to + extending the property list with the arguments. + ''' + setattr(namespace, self.dest, functools.reduce(lambda x, y: x | y, values, getattr(namespace, self.dest))) @@ -96,6 +118,12 @@ def __call__(self, parser, namespace, values, option_string=None): # Shaobo: shamelessly borrowed it from https://stackoverflow.com/a/55500795 class VProperty(Flag): + ''' + This class defines the properties that SMACK verifies. `NONE` is a special + value that does not correspond to any property. It's used simply to get + around the default value issue when the action similar to `extend`. + ''' + NONE = 0 ASSERTIONS = auto() VALID_DEREF = auto() @@ -123,9 +151,17 @@ def mem_safe_subprops(): return [VProperty.VALID_DEREF, VProperty.VALID_FREE, VProperty.MEMLEAK] def contains_mem_safe_props(self): + ''' + Test if a property is either memory-safety or any of its subproperties. + ''' + return bool(self & VProperty.MEMORY_SAFETY) def boogie_attr(self): + ''' + Return the attribute of Boogie assert command for certain property. + ''' + def get_attr_from_result(x): if x in VResult.MEMSAFETY_ERROR: return x.name.lower()[2:] @@ -146,6 +182,8 @@ def get_attr_from_result(x): 'property: %s' % self) def result(self): + '''Link SMACK properties with results''' + res = { VProperty.VALID_DEREF: VResult.INVALID_DEREF, VProperty.VALID_FREE: VResult.INVALID_FREE, From 79e23da295bce902b7ba6e9e4ad997ef97a5aeef Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 26 Oct 2020 20:45:42 -0600 Subject: [PATCH 059/109] Refactoring --- share/smack/svcomp/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index ebf6b8d44..56ad38b5b 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -79,9 +79,9 @@ def verify_bpl_svcomp(args): from smack.top import VProperty from smack.top import VResult - if (VProperty.MEMORY_SAFETY not in args.check - and VProperty.MEMLEAK not in args.check - and VProperty.INTEGER_OVERFLOW not in args.check): + if not (VProperty.MEMORY_SAFETY in args.check + or VProperty.MEMLEAK in args.check + or VProperty.INTEGER_OVERFLOW in args.check): inject_assert_false(args) corral_command = ["corral"] From 641b63e7cb8e1573a258977bfed2e42d44f2efed Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Tue, 27 Oct 2020 14:09:19 -0600 Subject: [PATCH 060/109] Remove extra options --- share/smack/top.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/share/smack/top.py b/share/smack/top.py index 2abc444a6..0edb65918 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -215,12 +215,6 @@ def arguments(): default='', help='additional compiler arguments (e.g., --clang-options="-w -g")') - frontend_group.add_argument( - '--crates', - default='*', - type=str, - help='Cargo crates to include in the analysis (comma separated)') - translate_group = parser.add_argument_group('translation options') translate_group.add_argument( From ed34b94129bf1c6d72ad32372316659b5b16d7cb Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Thu, 29 Oct 2020 21:39:00 -0600 Subject: [PATCH 061/109] Do not use sudo when prefix folder is given to build script In those situations a user typically wants to install SMACK into a user folder, where sudo is not needed. --- bin/build.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/build.sh b/bin/build.sh index 45ccad045..b1d24f671 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -470,7 +470,12 @@ if [ ${BUILD_SMACK} -eq 1 ] ; then cd ${SMACK_DIR}/build cmake ${CMAKE_INSTALL_PREFIX} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Debug .. -G Ninja ninja - sudo ninja install + + if [ -n "${CMAKE_INSTALL_PREFIX}" ] ; then + ninja install + else + sudo ninja install + fi puts "Configuring shell environment" source ${SMACKENV} From afd26dbd8d1cd3b1e428e0d3c084880e344aa865 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sat, 31 Oct 2020 13:41:33 -0600 Subject: [PATCH 062/109] Enable bit-vectors when overflow checking is used in SVCOMP --- share/smack/svcomp/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 56ad38b5b..076a4eb7b 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -23,6 +23,9 @@ def svcomp_frontend(input_file, args): # check svcomp properties and set flags accordingly svcomp_check_property(args) + if smack.top.VProperty.INTEGER_OVERFLOW in args.check: + args.integer_encoding = 'bit-vector' + name, ext = os.path.splitext(os.path.basename(args.input_files[0])) args.orig_files = list(args.input_files) From a55f3ee839dcad912798d2e5afd7c04633d36896 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 2 Nov 2020 09:06:04 -0700 Subject: [PATCH 063/109] Do not check for full-blown memory safety in SVCOMP --- share/smack/svcomp/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 076a4eb7b..20653d45f 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -54,7 +54,7 @@ def svcomp_check_property(args): from smack.top import VProperty from smack.top import VResult if "valid-deref" in prop: - args.check = VProperty.MEMORY_SAFETY + args.check = VProperty.VALID_DEREF elif "valid-memcleanup" in prop: args.check = VProperty.MEMLEAK elif "overflow" in prop: From 31a8e0b9fb51e0886a6efbd453d51b1c78593b94 Mon Sep 17 00:00:00 2001 From: Zvonimir Rakamaric Date: Thu, 5 Nov 2020 19:21:07 -0700 Subject: [PATCH 064/109] Improving sign vs unsign integer constant heuristics LLVM type system does not distinguish between signed and unsigned integers. So for the most part we cannot know for an integer constant if it should be interpreted as a signed or unsigned integer. This commit attempts to improve the used heuristics. --- include/smack/SmackRep.h | 9 ++++--- lib/smack/SmackRep.cpp | 37 ++++++++++++++++++++------- share/smack/include/smack.h | 4 ++- test/rust/{basic => failing}/arith.rs | 0 4 files changed, 37 insertions(+), 13 deletions(-) rename test/rust/{basic => failing}/arith.rs (100%) diff --git a/include/smack/SmackRep.h b/include/smack/SmackRep.h index 53043330f..b39048053 100644 --- a/include/smack/SmackRep.h +++ b/include/smack/SmackRep.h @@ -84,7 +84,8 @@ class SmackRep { const Expr *cast(unsigned opcode, const llvm::Value *v, const llvm::Type *t); bool isFpArithOp(unsigned opcode); const Expr *bop(unsigned opcode, const llvm::Value *lhs, - const llvm::Value *rhs, const llvm::Type *t); + const llvm::Value *rhs, const llvm::Type *t, + bool isUnsigned = false); const Expr *uop(const llvm::Value *op); const Expr *cmp(unsigned predicate, const llvm::Value *lhs, const llvm::Value *rhs, bool isUnsigned); @@ -128,7 +129,8 @@ class SmackRep { std::string type(const llvm::Type *t); std::string type(const llvm::Value *v); - const Expr *lit(const llvm::Value *v, bool isUnsigned = false); + const Expr *lit(const llvm::Value *v, bool isUnsigned = false, + bool isCmpInst = false); const Expr *lit(const llvm::Value *v, unsigned flag); const Expr *ptrArith(const llvm::GetElementPtrInst *I); @@ -137,7 +139,8 @@ class SmackRep { ptrArith(const llvm::Value *p, std::vector> args); - const Expr *expr(const llvm::Value *v, bool isConstIntUnsigned = false); + const Expr *expr(const llvm::Value *v, bool isConstIntUnsigned = false, + bool isCmpInst = false); const Expr *cast(const llvm::Instruction *I); const Expr *cast(const llvm::ConstantExpr *CE); diff --git a/lib/smack/SmackRep.cpp b/lib/smack/SmackRep.cpp index e78b5513b..d961d9533 100644 --- a/lib/smack/SmackRep.cpp +++ b/lib/smack/SmackRep.cpp @@ -624,13 +624,22 @@ const Expr *SmackRep::integerLit(long long v, unsigned width) { } } -const Expr *SmackRep::lit(const llvm::Value *v, bool isUnsigned) { +const Expr *SmackRep::lit(const llvm::Value *v, bool isUnsigned, + bool isCmpInst) { using namespace llvm; if (const ConstantInt *ci = llvm::dyn_cast(v)) { const APInt &API = ci->getValue(); unsigned width = ci->getBitWidth(); - bool neg = isUnsigned ? false : width > 1 && ci->isNegative(); + + // This is heuristics for choosing between generating an unsigned vs + // signed constant (since LLVM does not keep track of that). + // Signed values -1 is special since it appears often because i-- + // gets translated into i + (-1), and so in that context it should + // be a signed integer. + bool neg = width > 1 && + (isUnsigned ? (isCmpInst ? false : API.getSExtValue() == -1) + : ci->isNegative()); std::string str = (neg ? API.abs() : API).toString(10, false); const Expr *e = SmackOptions::BitPrecise ? Expr::lit(str, width) : Expr::lit(str, 0); @@ -784,7 +793,8 @@ const Expr *SmackRep::ptrArith( return e; } -const Expr *SmackRep::expr(const llvm::Value *v, bool isConstIntUnsigned) { +const Expr *SmackRep::expr(const llvm::Value *v, bool isConstIntUnsigned, + bool isCmpInst) { using namespace llvm; if (isa(v)) { @@ -827,7 +837,7 @@ const Expr *SmackRep::expr(const llvm::Value *v, bool isConstIntUnsigned) { } } else if (const ConstantInt *ci = dyn_cast(constant)) { - return lit(ci, isConstIntUnsigned); + return lit(ci, isConstIntUnsigned, isCmpInst); } else if (const ConstantFP *cf = dyn_cast(constant)) { return lit(cf); @@ -907,11 +917,19 @@ const Expr *SmackRep::bop(const llvm::ConstantExpr *CE) { const Expr *SmackRep::bop(const llvm::BinaryOperator *BO) { return bop(BO->getOpcode(), BO->getOperand(0), BO->getOperand(1), - BO->getType()); + BO->getType(), !BO->hasNoSignedWrap()); } const Expr *SmackRep::bop(unsigned opcode, const llvm::Value *lhs, - const llvm::Value *rhs, const llvm::Type *t) { + const llvm::Value *rhs, const llvm::Type *t, + bool isUnsigned) { + if (opcode == llvm::Instruction::SDiv || opcode == llvm::Instruction::SRem) { + isUnsigned = false; + } else if (opcode == llvm::Instruction::UDiv || + opcode == llvm::Instruction::URem) { + isUnsigned = true; + } + std::string fn = Naming::INSTRUCTION_TABLE.at(opcode); if (isFpArithOp(opcode)) { if (SmackOptions::FloatEnabled) { @@ -921,7 +939,8 @@ const Expr *SmackRep::bop(unsigned opcode, const llvm::Value *lhs, return Expr::fn(opName(fn, {t}), expr(lhs), expr(rhs)); } } - return Expr::fn(opName(fn, {t}), expr(lhs), expr(rhs)); + return Expr::fn(opName(fn, {t}), expr(lhs, isUnsigned), + expr(rhs, isUnsigned)); } const Expr *SmackRep::uop(const llvm::ConstantExpr *CE) { @@ -951,8 +970,8 @@ const Expr *SmackRep::cmp(unsigned predicate, const llvm::Value *lhs, const llvm::Value *rhs, bool isUnsigned) { std::string fn = opName(Naming::CMPINST_TABLE.at(predicate), {lhs->getType()}); - const Expr *e1 = expr(lhs, isUnsigned); - const Expr *e2 = expr(rhs, isUnsigned); + const Expr *e1 = expr(lhs, isUnsigned, true); + const Expr *e2 = expr(rhs, isUnsigned, true); if (lhs->getType()->isFloatingPointTy()) return Expr::ifThenElse(Expr::fn(fn + ".bool", e1, e2), integerLit(1ULL, 1), integerLit(0ULL, 1)); diff --git a/share/smack/include/smack.h b/share/smack/include/smack.h index 60527f66a..cd29d2465 100644 --- a/share/smack/include/smack.h +++ b/share/smack/include/smack.h @@ -19,10 +19,12 @@ extern "C" { #define __builtin_expect __builtinx_expect #define __builtin_memcpy __builtinx_memcpy #define __builtin_va_start __builtinx_va_start +#define __builtin_va_arg(ap, t) __builtinx_va_arg(ap) #define __builtin_object_size __builtinx_object_size -// For handling of va_start macro +// For handling of va macros void __builtinx_va_start(char *, char *); +void *__builtinx_va_arg(char *); #endif void __SMACK_code(const char *fmt, ...); diff --git a/test/rust/basic/arith.rs b/test/rust/failing/arith.rs similarity index 100% rename from test/rust/basic/arith.rs rename to test/rust/failing/arith.rs From ffcdf263c2be153a15580ae08a384f465d5e7d27 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Fri, 6 Nov 2020 23:47:25 -0700 Subject: [PATCH 065/109] Fixed incorrect reliance on instruction order for overflow checking We used to assume two extractvalue instructions that use the overflow checking intrinsics are consecutive, which may not be the case. This commit remove the reliance on this assumption. --- lib/smack/IntegerOverflowChecker.cpp | 76 ++++++++++++++-------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/lib/smack/IntegerOverflowChecker.cpp b/lib/smack/IntegerOverflowChecker.cpp index 848e95b60..0d1679596 100644 --- a/lib/smack/IntegerOverflowChecker.cpp +++ b/lib/smack/IntegerOverflowChecker.cpp @@ -135,33 +135,27 @@ bool IntegerOverflowChecker::runOnModule(Module &m) { if (Naming::isSmackName(F.getName())) continue; for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { - // Add check for UBSan left shift/signed division when needed - if (SmackOptions::IntegerOverflow) { - if (auto chkshft = dyn_cast(&*I)) { - Function *chkfn = chkshft->getCalledFunction(); - if (chkfn && chkfn->hasName() && - (chkfn->getName().find("__ubsan_handle_shift_out_of_bounds") != - std::string::npos || - chkfn->getName().find("__ubsan_handle_divrem_overflow") != - std::string::npos)) { + if (auto ci = dyn_cast(&*I)) { + Function *f = ci->getCalledFunction(); + if (f && f->hasName()) { + std::string fn = f->getName(); + if (fn.find("__ubsan_handle_shift_out_of_bounds") != + std::string::npos || + fn.find("__ubsan_handle_divrem_overflow") != std::string::npos) { // If the call to __ubsan_handle_* is reachable, // then an overflow is possible. - ConstantInt *flag = - ConstantInt::getTrue(chkshft->getFunction()->getContext()); - addCheck(co, flag, &*I); - addBlockingAssume(va, flag, &*I); - I->replaceAllUsesWith(flag); - instToErase.push_back(&*I); + if (SmackOptions::IntegerOverflow) { + // Add check for UBSan left shift/signed division when needed + ConstantInt *flag = + ConstantInt::getTrue(ci->getFunction()->getContext()); + addCheck(co, flag, ci); + addBlockingAssume(va, flag, ci); + ci->replaceAllUsesWith(flag); + instToErase.push_back(ci); + } } - } - } - if (auto ei = dyn_cast(&*I)) { - if (auto ci = dyn_cast(ei->getAggregateOperand())) { - Function *f = ci->getCalledFunction(); SmallVector info; - if (f && f->hasName() && - OVERFLOW_INTRINSICS.match(f->getName(), &info) && - ei->getIndices()[0] == 1) { + if (OVERFLOW_INTRINSICS.match(f->getName(), &info)) { /* * If ei is an ExtractValueInst whose value flows from an LLVM * checked value intrinsic f, then we do the following: @@ -181,29 +175,35 @@ bool IntegerOverflowChecker::runOnModule(Module &m) { bool isSigned = (info[1] == "s"); std::string op = info[2]; int bits = std::stoi(info[3]); - Instruction *prev = &*std::prev(I); Value *eo1 = - extendBitWidth(ci->getArgOperand(0), bits, isSigned, &*I); + extendBitWidth(ci->getArgOperand(0), bits, isSigned, ci); Value *eo2 = - extendBitWidth(ci->getArgOperand(1), bits, isSigned, &*I); + extendBitWidth(ci->getArgOperand(1), bits, isSigned, ci); SDEBUG(errs() << "Processing operator: " << op << "\n"); assert(INSTRUCTION_TABLE.count(op) != 0 && "Operator must be present in our instruction table."); BinaryOperator *ai = BinaryOperator::Create( - INSTRUCTION_TABLE.at(op), eo1, eo2, "", &*I); - if (auto pei = dyn_cast_or_null(prev)) { - if (ci == dyn_cast(pei->getAggregateOperand())) { - Value *r = createResult(ai, bits, &*I); - prev->replaceAllUsesWith(r); - instToErase.push_back(prev); + INSTRUCTION_TABLE.at(op), eo1, eo2, "", ci); + Value *r = createResult(ai, bits, &*I); + BinaryOperator *flag = createFlag(ai, bits, isSigned, ci); + if (SmackOptions::IntegerOverflow) + addCheck(co, flag, ci); + for (auto U : ci->users()) { + if (ExtractValueInst *ei = dyn_cast(U)) { + if (ei->getNumIndices() == 1) { + if (ei->getIndices()[0] == 0) + // value part + ei->replaceAllUsesWith(r); + else if (ei->getIndices()[0] == 1) { + // flag part + addBlockingAssume(va, flag, ei); + ei->replaceAllUsesWith(flag); + } else + llvm_unreachable("Unexpected extractvalue inst!"); + instToErase.push_back(ei); + } } } - BinaryOperator *flag = createFlag(ai, bits, isSigned, &*I); - if (SmackOptions::IntegerOverflow) - addCheck(co, flag, &*I); - addBlockingAssume(va, flag, &*I); - I->replaceAllUsesWith(flag); - instToErase.push_back(&*I); instToErase.push_back(ci); } } From 79a2fa3fa11725a48af6d46e98d0621fd8a8c04b Mon Sep 17 00:00:00 2001 From: Shaobo <5892703+shaobo-he@users.noreply.github.com> Date: Sat, 7 Nov 2020 08:35:56 -0800 Subject: [PATCH 066/109] Fixed invalid translation/assertion failure related to inline assembly Inline assembly with side effects do not have functions being called values. This triggers invalid translation by the `Devirt` pass and assertion failure in `SmackInstGenerator`. --- lib/smack/SmackInstGenerator.cpp | 14 ++++++++------ lib/utils/Devirt.cpp | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index 16c002dd0..9d34925ca 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -646,6 +646,13 @@ void SmackInstGenerator::visitSelectInst(llvm::SelectInst &i) { void SmackInstGenerator::visitCallInst(llvm::CallInst &ci) { processInstruction(ci); + if (ci.isInlineAsm()) { + SmackWarnings::warnUnsound("inline asm call " + i2s(ci), currBlock, &ci, + ci.getType()->isVoidTy()); + emit(Stmt::skip()); + return; + } + Function *f = ci.getCalledFunction(); if (!f) { assert(ci.getCalledValue() && "Called value is null"); @@ -654,12 +661,7 @@ void SmackInstGenerator::visitCallInst(llvm::CallInst &ci) { std::string name = f->hasName() ? f->getName() : ""; - if (ci.isInlineAsm()) { - SmackWarnings::warnUnsound("inline asm call " + i2s(ci), currBlock, &ci, - ci.getType()->isVoidTy()); - emit(Stmt::skip()); - - } else if (SmackOptions::RustPanics && isRustPanic(name)) { + if (SmackOptions::RustPanics && isRustPanic(name)) { // Convert Rust's panic functions into assertion violations emit(Stmt::assert_(Expr::lit(false), {Attr::attr(Naming::RUST_PANIC_ANNOTATION)})); diff --git a/lib/utils/Devirt.cpp b/lib/utils/Devirt.cpp index ecb281a10..5be7fe530 100644 --- a/lib/utils/Devirt.cpp +++ b/lib/utils/Devirt.cpp @@ -456,7 +456,7 @@ Devirtualize::processCallSite (CallSite &CS) { // First, determine if this is a direct call. If so, then just ignore it. // Value * CalledValue = CS.getCalledValue(); - if (isa(CalledValue->stripPointerCastsAndAliases())) + if (!CS.isIndirectCall()) return; // From dc16dd5e08583e904a626c23e86ad89178d3e932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mark=20S=2E=20Baranowski=20=28Marek=20Stanis=C5=82aw=20Bar?= =?UTF-8?q?anowski=29?= Date: Sat, 7 Nov 2020 09:57:54 -0700 Subject: [PATCH 067/109] Add a pass to transform certain bit-wise operations into integer operations Certain bit-vectors operations (and, shift) can be transformed into integer operations when one of the operands is a constant. That way in those situations we do not have to enable bit-vector reasoning. --- CMakeLists.txt | 2 + include/smack/RewriteBitwiseOps.h | 22 +++ lib/smack/RewriteBitwiseOps.cpp | 129 ++++++++++++++++++ test/c/special/assume.c | 4 +- test/c/special/assume2.c | 4 +- test/c/special/assume_check_fail.c | 4 +- test/c/special/assume_fail.c | 4 +- test/c/special/bitwise_and.c | 43 ++++++ test/c/special/bitwise_and_fail.c | 45 ++++++ test/c/special/bitwise_constant_shifts.c | 40 ++++++ test/c/special/bitwise_constant_shifts_fail.c | 42 ++++++ tools/llvm2bpl/llvm2bpl.cpp | 6 + 12 files changed, 337 insertions(+), 8 deletions(-) create mode 100644 include/smack/RewriteBitwiseOps.h create mode 100644 lib/smack/RewriteBitwiseOps.cpp create mode 100644 test/c/special/bitwise_and.c create mode 100644 test/c/special/bitwise_and_fail.c create mode 100644 test/c/special/bitwise_constant_shifts.c create mode 100644 test/c/special/bitwise_constant_shifts_fail.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 20b81f9c6..287516b98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,6 +131,7 @@ add_library(smackTranslator STATIC include/smack/VectorOperations.h include/smack/MemorySafetyChecker.h include/smack/IntegerOverflowChecker.h + include/smack/RewriteBitwiseOps.h include/smack/NormalizeLoops.h include/smack/RustFixes.h include/smack/SplitAggregateValue.h @@ -156,6 +157,7 @@ add_library(smackTranslator STATIC lib/smack/VectorOperations.cpp lib/smack/MemorySafetyChecker.cpp lib/smack/IntegerOverflowChecker.cpp + lib/smack/RewriteBitwiseOps.cpp lib/smack/NormalizeLoops.cpp lib/smack/RustFixes.cpp lib/smack/SplitAggregateValue.cpp diff --git a/include/smack/RewriteBitwiseOps.h b/include/smack/RewriteBitwiseOps.h new file mode 100644 index 000000000..7ee3b6238 --- /dev/null +++ b/include/smack/RewriteBitwiseOps.h @@ -0,0 +1,22 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +#ifndef REWRITEBITWISEOPS_H +#define REWRITEBITWISEOPS_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Pass.h" + +namespace smack { + +class RewriteBitwiseOps : public llvm::FunctionPass { +public: + static char ID; // Pass identification, replacement for typeid + RewriteBitwiseOps() : llvm::FunctionPass(ID) {} + virtual llvm::StringRef getPassName() const; + virtual bool runOnFunction(llvm::Function &f); +}; +} // namespace smack + +#endif // REWRITEBITWISEOPS_H diff --git a/lib/smack/RewriteBitwiseOps.cpp b/lib/smack/RewriteBitwiseOps.cpp new file mode 100644 index 000000000..48e352e8f --- /dev/null +++ b/lib/smack/RewriteBitwiseOps.cpp @@ -0,0 +1,129 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// + +// This pass converts bitwise operations with certain constant operands +// into equivalent integer operations. + +#include "smack/RewriteBitwiseOps.h" +#include "smack/Debug.h" +#include "smack/Naming.h" +#include "smack/SmackOptions.h" +#include "llvm/ADT/APInt.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include + +namespace smack { + +using namespace llvm; + +unsigned getOpBitWidth(const Value *V) { + const Type *T = V->getType(); + const IntegerType *iType = cast(T); + return iType->getBitWidth(); +} + +Optional getConstantIntValue(const Value *V) { + if (const ConstantInt *ci = dyn_cast(V)) { + const APInt &value = ci->getValue(); + return Optional(value); + } else { + return Optional(); + } +} + +bool isConstantInt(const Value *V) { + Optional constantValue = getConstantIntValue(V); + return constantValue.hasValue() && (*constantValue + 1).isPowerOf2(); +} + +bool RewriteBitwiseOps::runOnFunction(Function &f) { + if (Naming::isSmackName(f.getName())) + return false; + + std::vector instsFrom; + std::vector instsTo; + + for (inst_iterator I = inst_begin(f), E = inst_end(f); I != E; ++I) { + if (I->isShift()) { + BinaryOperator *bi = cast(&*I); + Value *amount = bi->getOperand(1); + + if (ConstantInt *ci = dyn_cast(amount)) { + unsigned opcode = bi->getOpcode(); + Instruction::BinaryOps op; + if (opcode == Instruction::AShr || opcode == Instruction::LShr) { + // Shifting right by a constant amount is equivalent to dividing by + // 2^amount + op = Instruction::SDiv; + } else if (opcode == Instruction::Shl) { + // Shifting left by a constant amount is equivalent to dividing by + // 2^amount + op = Instruction::Mul; + } + + auto lhs = bi->getOperand(0); + unsigned bitWidth = getOpBitWidth(lhs); + APInt rhsVal = APInt(bitWidth, "1", 10); + const APInt &value = ci->getValue(); + rhsVal <<= value; + Value *rhs = ConstantInt::get(ci->getType(), rhsVal); + Instruction *replacement = + BinaryOperator::Create(op, lhs, rhs, "", (Instruction *)nullptr); + instsFrom.push_back(&*I); + instsTo.push_back(replacement); + } + } + if (I->isBitwiseLogicOp()) { + // If the operation is a bit-wise `and' and the mask variable is constant, + // it may be possible to replace this operation with a remainder + // operation. If one argument has only ones, and they're only in the least + // significant bit, then the mask is 2^(number of ones) - 1. This is + // equivalent to the remainder when dividing by 2^(number of ones). + BinaryOperator *bi = cast(&*I); + unsigned opcode = bi->getOpcode(); + if (opcode == Instruction::And) { + Value *args[] = {bi->getOperand(0), bi->getOperand(1)}; + int maskOperand = -1; + + if (isConstantInt(args[0])) { + maskOperand = 0; + } else if (isConstantInt(args[1])) { + maskOperand = 1; + } else { + continue; + } + + auto lhs = args[1 - maskOperand]; + Value *rhs = ConstantInt::get( + f.getContext(), *getConstantIntValue(args[maskOperand]) + 1); + Instruction *replacement = BinaryOperator::Create( + Instruction::URem, lhs, rhs, "", (Instruction *)nullptr); + instsFrom.push_back(&*I); + instsTo.push_back(replacement); + } + } + } + + for (size_t i = 0; i < instsFrom.size(); ++i) { + ReplaceInstWithInst(instsFrom[i], instsTo[i]); + } + + return true; +} + +// Pass ID variable +char RewriteBitwiseOps::ID = 0; + +StringRef RewriteBitwiseOps::getPassName() const { + return "Translate bitwise operations with constant arguments to integer " + "operations"; +} +} // namespace smack diff --git a/test/c/special/assume.c b/test/c/special/assume.c index eee18cc4d..cb25eee4c 100644 --- a/test/c/special/assume.c +++ b/test/c/special/assume.c @@ -7,6 +7,6 @@ int main(void) { unsigned int y = 2 * (unsigned int)__VERIFIER_nondet_unsigned_short(); // This assumption is used for verification, even though // integer-encoding=bit-vector is not enabled, the assertion will pass. - __builtin_assume((y & 1) == 0); - assert((y & 1) == 0); + __builtin_assume((y | 1) == (y + 1)); + assert((y | 1) == (y + 1)); } diff --git a/test/c/special/assume2.c b/test/c/special/assume2.c index 03b70c663..9df5ec7c8 100644 --- a/test/c/special/assume2.c +++ b/test/c/special/assume2.c @@ -7,6 +7,6 @@ int main(void) { unsigned int y = (2 * (unsigned int)__VERIFIER_nondet_unsigned_short()) + 1; // This assumption is used for verification, even though the assumption // is false, the assertion will pass. - __builtin_assume((y & 1) == 0); - assert((y & 1) == 0); + __builtin_assume((y | 1) == (y + 1)); + assert((y | 1) == (y + 1)); } diff --git a/test/c/special/assume_check_fail.c b/test/c/special/assume_check_fail.c index f84470d22..5abfcba79 100644 --- a/test/c/special/assume_check_fail.c +++ b/test/c/special/assume_check_fail.c @@ -9,6 +9,6 @@ int main(void) { // This assumption is checked at verification time, and since // integer-encoding=bit-vector is enabled, and y is clearly odd, the // assumption should be shown false. - __builtin_assume((y & 1) == 0); - assert((y & 1) == 0); + __builtin_assume((y | 1) == (y + 1)); + assert((y | 1) == (y + 1)); } diff --git a/test/c/special/assume_fail.c b/test/c/special/assume_fail.c index 8ab1c4e1b..5390efeb1 100644 --- a/test/c/special/assume_fail.c +++ b/test/c/special/assume_fail.c @@ -7,6 +7,6 @@ int main(void) { unsigned int y = 2 * (unsigned int)__VERIFIER_nondet_unsigned_short(); // This assumption is not used, and since integer-encoding=bit-vector is // not enabled, verification will fail. - __builtin_assume((y & 1) == 0); - assert((y & 1) == 0); + __builtin_assume((y | 1) == (y + 1)); + assert((y | 1) == (y + 1)); } diff --git a/test/c/special/bitwise_and.c b/test/c/special/bitwise_and.c new file mode 100644 index 000000000..2198021ed --- /dev/null +++ b/test/c/special/bitwise_and.c @@ -0,0 +1,43 @@ +#include "smack.h" + +// @expect verified + +int main(void) { + unsigned char x = (unsigned char)__VERIFIER_nondet_unsigned_char(); + { // y = 0 + __VERIFIER_assert((x & 0) == (x % (0 + 1))); + __VERIFIER_assert((0 & x) == (x % (0 + 1))); + } + { // y = 1 + __VERIFIER_assert((x & 1) == (x % (1 + 1))); + __VERIFIER_assert((1 & x) == (x % (1 + 1))); + } + { // y = 3 + __VERIFIER_assert((x & 3) == (x % (3 + 1))); + __VERIFIER_assert((3 & x) == (x % (3 + 1))); + } + { // y = 7 + __VERIFIER_assert((x & 7) == (x % (7 + 1))); + __VERIFIER_assert((7 & x) == (x % (7 + 1))); + } + { // y = 15 + __VERIFIER_assert((x & 15) == (x % (15 + 1))); + __VERIFIER_assert((15 & x) == (x % (15 + 1))); + } + { // y = 31 + __VERIFIER_assert((x & 31) == (x % (31 + 1))); + __VERIFIER_assert((31 & x) == (x % (31 + 1))); + } + { // y = 63 + __VERIFIER_assert((x & 63) == (x % (63 + 1))); + __VERIFIER_assert((63 & x) == (x % (63 + 1))); + } + { // y = 127 + __VERIFIER_assert((x & 127) == (x % (127 + 1))); + __VERIFIER_assert((127 & x) == (x % (127 + 1))); + } + { // y = 255 + __VERIFIER_assert((x & 255) == x); + __VERIFIER_assert((255 & x) == x); + } +} diff --git a/test/c/special/bitwise_and_fail.c b/test/c/special/bitwise_and_fail.c new file mode 100644 index 000000000..4aa0f5415 --- /dev/null +++ b/test/c/special/bitwise_and_fail.c @@ -0,0 +1,45 @@ +#include "smack.h" + +// @expect error + +int main(void) { + unsigned char x = (unsigned char)__VERIFIER_nondet_unsigned_char(); + int cond = 0; + { // y = 0 + cond = cond || ((x & 0) != (x % (0 + 1))); + cond = cond || ((0 & x) != (x % (0 + 1))); + } + { // y = 1 + cond = cond || ((x & 1) != (x % (1 + 1))); + cond = cond || ((1 & x) != (x % (1 + 1))); + } + { // y = 3 + cond = cond || ((x & 3) != (x % (3 + 1))); + cond = cond || ((3 & x) != (x % (3 + 1))); + } + { // y = 7 + cond = cond || ((x & 7) != (x % (7 + 1))); + cond = cond || ((7 & x) != (x % (7 + 1))); + } + { // y = 15 + cond = cond || ((x & 15) != (x % (15 + 1))); + cond = cond || ((15 & x) != (x % (15 + 1))); + } + { // y = 31 + cond = cond || ((x & 31) != (x % (31 + 1))); + cond = cond || ((31 & x) != (x % (31 + 1))); + } + { // y = 63 + cond = cond || ((x & 63) != (x % (63 + 1))); + cond = cond || ((63 & x) != (x % (63 + 1))); + } + { // y = 127 + cond = cond || ((x & 127) != (x % (127 + 1))); + cond = cond || ((127 & x) != (x % (127 + 1))); + } + { // y = 255 + cond = cond || ((x & 255) != x); + cond = cond || ((255 & x) != x); + } + __VERIFIER_assert(cond); +} diff --git a/test/c/special/bitwise_constant_shifts.c b/test/c/special/bitwise_constant_shifts.c new file mode 100644 index 000000000..b467b49d9 --- /dev/null +++ b/test/c/special/bitwise_constant_shifts.c @@ -0,0 +1,40 @@ +#include "smack.h" + +// @expect verified + +int main(void) { + unsigned char x = __VERIFIER_nondet_unsigned_char(); + { // y = 0 + __VERIFIER_assert((x >> 0) == (x / 1)); + __VERIFIER_assert((x << 0) == (x * 1)); + } + { // y = 1 + __VERIFIER_assert((x >> 1) == (x / 2)); + __VERIFIER_assert((x << 1) == (x * 2)); + } + { // y = 3 + __VERIFIER_assert((x >> 3) == (x / 8)); + __VERIFIER_assert((x << 3) == (x * 8)); + } + { // y = 4 + __VERIFIER_assert((x >> 4) == (x / 16)); + __VERIFIER_assert((x << 4) == (x * 16)); + } + { // y = 5 + __VERIFIER_assert((x >> 5) == (x / 32)); + __VERIFIER_assert((x << 5) == (x * 32)); + } + { // y = 6 + __VERIFIER_assert((x >> 6) == (x / 64)); + __VERIFIER_assert((x << 6) == (x * 64)); + } + { // y = 7 + __VERIFIER_assert((x >> 7) == (x / 128)); + __VERIFIER_assert((x << 7) == (x * 128)); + } + { // y = 8 + __VERIFIER_assert((x >> 8) == 0); + // This may not be possible to handle correctly. + __VERIFIER_assert((x << 8) == x * 128 + x * 128); + } +} diff --git a/test/c/special/bitwise_constant_shifts_fail.c b/test/c/special/bitwise_constant_shifts_fail.c new file mode 100644 index 000000000..fbc1834a0 --- /dev/null +++ b/test/c/special/bitwise_constant_shifts_fail.c @@ -0,0 +1,42 @@ +#include "smack.h" + +// @expect error + +int main(void) { + unsigned char x = __VERIFIER_nondet_unsigned_char(); + int cond = 0; + { // y = 0 + cond = cond || ((x >> 0) != (x / 1)); + cond = cond || ((x << 0) != (x * 1)); + } + { // y = 1 + cond = cond || ((x >> 1) != (x / 2)); + cond = cond || ((x << 1) != (x * 2)); + } + { // y = 3 + cond = cond || ((x >> 3) != (x / 8)); + cond = cond || ((x << 3) != (x * 8)); + } + { // y = 4 + cond = cond || ((x >> 4) != (x / 16)); + cond = cond || ((x << 4) != (x * 16)); + } + { // y = 5 + cond = cond || ((x >> 5) != (x / 32)); + cond = cond || ((x << 5) != (x * 32)); + } + { // y = 6 + cond = cond || ((x >> 6) != (x / 64)); + cond = cond || ((x << 6) != (x * 64)); + } + { // y = 7 + cond = cond || ((x >> 7) != (x / 128)); + cond = cond || ((x << 7) != (x * 128)); + } + { // y = 8 + cond = cond || ((x >> 8) != 0); + // This may not be possible to handle correctly. + cond = cond || ((x << 8) != x * 128 + x * 128); + } + __VERIFIER_assert(cond); +} diff --git a/tools/llvm2bpl/llvm2bpl.cpp b/tools/llvm2bpl/llvm2bpl.cpp index c659ead60..38f348c3d 100644 --- a/tools/llvm2bpl/llvm2bpl.cpp +++ b/tools/llvm2bpl/llvm2bpl.cpp @@ -35,6 +35,7 @@ #include "smack/MemorySafetyChecker.h" #include "smack/NormalizeLoops.h" #include "smack/RemoveDeadDefs.h" +#include "smack/RewriteBitwiseOps.h" #include "smack/RustFixes.h" #include "smack/SimplifyLibCalls.h" #include "smack/SmackModuleGenerator.h" @@ -195,6 +196,11 @@ int main(int argc, char **argv) { pass_manager.add(new smack::IntegerOverflowChecker()); + if (!(smack::SmackOptions::BitPrecise || + smack::SmackOptions::BitPrecisePointers)) { + pass_manager.add(new smack::RewriteBitwiseOps()); + } + if (smack::SmackOptions::AddTiming) { Triple ModuleTriple(module->getTargetTriple()); assert( From 2d6d7d273edd4250bbf96207b9f7db62873585b0 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 9 Nov 2020 19:02:57 -0700 Subject: [PATCH 068/109] Provided a model for va_arg function Given that we are not completely modeling functions with variable number of arguments, we should block execution when va_arg is hit. --- share/smack/lib/smack.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index 5643afdb4..efa420c4c 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -33,6 +33,11 @@ * */ +void *__builtinx_va_arg(char *x) { + __SMACK_code("assume false;"); + return 0; +} + void __VERIFIER_assume(int x) { #if !RUST_EXEC __SMACK_dummy(x); From 5c6cbcbec8d78a6ee8bd7d800a5c375e6fa4f11d Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Mon, 9 Nov 2020 15:28:10 -0700 Subject: [PATCH 069/109] Implemented using procedures for bit-wise operations In the integer reasoning mode, I now provided integer-based implementations for bit-wise and and or operations. The implementations are done in C in the SMACK library file. Then, when the operations are encountered, the appropriate procedures get invoked. --- include/smack/RewriteBitwiseOps.h | 9 +- lib/smack/RewriteBitwiseOps.cpp | 136 ++++--- share/smack/lib/smack.c | 368 ++++++++++++++++++ test/c/{special => failing}/bitwise_and.c | 0 .../c/{special => failing}/bitwise_and_fail.c | 0 5 files changed, 449 insertions(+), 64 deletions(-) rename test/c/{special => failing}/bitwise_and.c (100%) rename test/c/{special => failing}/bitwise_and_fail.c (100%) diff --git a/include/smack/RewriteBitwiseOps.h b/include/smack/RewriteBitwiseOps.h index 7ee3b6238..da009d209 100644 --- a/include/smack/RewriteBitwiseOps.h +++ b/include/smack/RewriteBitwiseOps.h @@ -4,18 +4,17 @@ #ifndef REWRITEBITWISEOPS_H #define REWRITEBITWISEOPS_H -#include "llvm/IR/Function.h" -#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" #include "llvm/Pass.h" namespace smack { -class RewriteBitwiseOps : public llvm::FunctionPass { +class RewriteBitwiseOps : public llvm::ModulePass { public: static char ID; // Pass identification, replacement for typeid - RewriteBitwiseOps() : llvm::FunctionPass(ID) {} + RewriteBitwiseOps() : llvm::ModulePass(ID) {} virtual llvm::StringRef getPassName() const; - virtual bool runOnFunction(llvm::Function &f); + virtual bool runOnModule(llvm::Module &m); }; } // namespace smack diff --git a/lib/smack/RewriteBitwiseOps.cpp b/lib/smack/RewriteBitwiseOps.cpp index 48e352e8f..a79b832db 100644 --- a/lib/smack/RewriteBitwiseOps.cpp +++ b/lib/smack/RewriteBitwiseOps.cpp @@ -13,7 +13,6 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" -#include "llvm/IR/Module.h" #include "llvm/IR/ValueSymbolTable.h" #include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" @@ -44,70 +43,89 @@ bool isConstantInt(const Value *V) { return constantValue.hasValue() && (*constantValue + 1).isPowerOf2(); } -bool RewriteBitwiseOps::runOnFunction(Function &f) { - if (Naming::isSmackName(f.getName())) - return false; - +bool RewriteBitwiseOps::runOnModule(Module &m) { std::vector instsFrom; std::vector instsTo; - for (inst_iterator I = inst_begin(f), E = inst_end(f); I != E; ++I) { - if (I->isShift()) { - BinaryOperator *bi = cast(&*I); - Value *amount = bi->getOperand(1); - - if (ConstantInt *ci = dyn_cast(amount)) { - unsigned opcode = bi->getOpcode(); - Instruction::BinaryOps op; - if (opcode == Instruction::AShr || opcode == Instruction::LShr) { - // Shifting right by a constant amount is equivalent to dividing by - // 2^amount - op = Instruction::SDiv; - } else if (opcode == Instruction::Shl) { - // Shifting left by a constant amount is equivalent to dividing by - // 2^amount - op = Instruction::Mul; + for (auto &F : m) { + if (Naming::isSmackName(F.getName())) + continue; + for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { + if (I->isShift()) { + BinaryOperator *bi = cast(&*I); + Value *amount = bi->getOperand(1); + + if (ConstantInt *ci = dyn_cast(amount)) { + unsigned opcode = bi->getOpcode(); + Instruction::BinaryOps op; + if (opcode == Instruction::AShr || opcode == Instruction::LShr) { + // Shifting right by a constant amount is equivalent to dividing by + // 2^amount + op = Instruction::SDiv; + } else if (opcode == Instruction::Shl) { + // Shifting left by a constant amount is equivalent to dividing by + // 2^amount + op = Instruction::Mul; + } + + auto lhs = bi->getOperand(0); + unsigned bitWidth = getOpBitWidth(lhs); + APInt rhsVal = APInt(bitWidth, "1", 10); + const APInt &value = ci->getValue(); + rhsVal <<= value; + Value *rhs = ConstantInt::get(ci->getType(), rhsVal); + Instruction *replacement = BinaryOperator::Create(op, lhs, rhs, ""); + instsFrom.push_back(&*I); + instsTo.push_back(replacement); } - - auto lhs = bi->getOperand(0); - unsigned bitWidth = getOpBitWidth(lhs); - APInt rhsVal = APInt(bitWidth, "1", 10); - const APInt &value = ci->getValue(); - rhsVal <<= value; - Value *rhs = ConstantInt::get(ci->getType(), rhsVal); - Instruction *replacement = - BinaryOperator::Create(op, lhs, rhs, "", (Instruction *)nullptr); - instsFrom.push_back(&*I); - instsTo.push_back(replacement); } - } - if (I->isBitwiseLogicOp()) { - // If the operation is a bit-wise `and' and the mask variable is constant, - // it may be possible to replace this operation with a remainder - // operation. If one argument has only ones, and they're only in the least - // significant bit, then the mask is 2^(number of ones) - 1. This is - // equivalent to the remainder when dividing by 2^(number of ones). - BinaryOperator *bi = cast(&*I); - unsigned opcode = bi->getOpcode(); - if (opcode == Instruction::And) { - Value *args[] = {bi->getOperand(0), bi->getOperand(1)}; - int maskOperand = -1; - - if (isConstantInt(args[0])) { - maskOperand = 0; - } else if (isConstantInt(args[1])) { - maskOperand = 1; - } else { - continue; + if (I->isBitwiseLogicOp()) { + // If the operation is a bit-wise `and' and the mask variable is + // constant, it may be possible to replace this operation with a + // remainder operation. If one argument has only ones, and they're only + // in the least significant bit, then the mask is 2^(number of ones) + // - 1. This is equivalent to the remainder when dividing by 2^(number + // of ones). + BinaryOperator *bi = cast(&*I); + unsigned opcode = bi->getOpcode(); + if (opcode == Instruction::And) { + Value *args[] = {bi->getOperand(0), bi->getOperand(1)}; + int maskOperand = -1; + + if (isConstantInt(args[0])) { + maskOperand = 0; + } + // Zvonimir: Right-side constants do not work well on SVCOMP + // } else if (isConstantInt(args[1])) { + // maskOperand = 1; + // } + + if (maskOperand == -1) { + Function *co = m.getFunction("__SMACK_and"); + assert(co != NULL && "Function __SMACK_and should be present."); + std::vector args; + args.push_back(bi->getOperand(0)); + args.push_back(bi->getOperand(1)); + instsFrom.push_back(&*I); + instsTo.push_back(CallInst::Create(co, args, "")); + } else { + auto lhs = args[1 - maskOperand]; + Value *rhs = ConstantInt::get( + m.getContext(), *getConstantIntValue(args[maskOperand]) + 1); + Instruction *replacement = + BinaryOperator::Create(Instruction::URem, lhs, rhs, ""); + instsFrom.push_back(&*I); + instsTo.push_back(replacement); + } + } else if (opcode == Instruction::Or) { + Function *co = m.getFunction("__SMACK_or"); + assert(co != NULL && "Function __SMACK_or should be present."); + std::vector args; + args.push_back(bi->getOperand(0)); + args.push_back(bi->getOperand(1)); + instsFrom.push_back(&*I); + instsTo.push_back(CallInst::Create(co, args, "")); } - - auto lhs = args[1 - maskOperand]; - Value *rhs = ConstantInt::get( - f.getContext(), *getConstantIntValue(args[maskOperand]) + 1); - Instruction *replacement = BinaryOperator::Create( - Instruction::URem, lhs, rhs, "", (Instruction *)nullptr); - instsFrom.push_back(&*I); - instsTo.push_back(replacement); } } } diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index efa420c4c..c2185f713 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -83,6 +83,374 @@ EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long); EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long, int); #endif // RUST_EXEC +int __SMACK_and(int a, int b) { + int c = 0; + + __VERIFIER_assume(a != 0 && b != 0); + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + return c; +} + +int __SMACK_or(int a, int b) { + int c = 0; + + __VERIFIER_assume(a != 0 && b != 0); + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + return c; +} + void __SMACK_check_overflow(int flag) { __SMACK_dummy(flag); __SMACK_code("assert {:overflow} @ == $0;", flag); diff --git a/test/c/special/bitwise_and.c b/test/c/failing/bitwise_and.c similarity index 100% rename from test/c/special/bitwise_and.c rename to test/c/failing/bitwise_and.c diff --git a/test/c/special/bitwise_and_fail.c b/test/c/failing/bitwise_and_fail.c similarity index 100% rename from test/c/special/bitwise_and_fail.c rename to test/c/failing/bitwise_and_fail.c From a3886c8061cd41bc3571869094d0f7652e6f549d Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Tue, 10 Nov 2020 21:28:27 -0700 Subject: [PATCH 070/109] Fixed assume regressions to use xor Now we are partially modeling and and or bit-wise operations, and hence previous versions of these regressions were failing. --- test/c/special/assume.c | 8 +++++--- test/c/special/assume2.c | 7 ++++--- test/c/special/assume_check.c | 8 +++++--- test/c/special/assume_check2.c | 10 +++++----- test/c/special/assume_check_fail.c | 12 +++++++----- test/c/special/assume_fail.c | 8 +++++--- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/test/c/special/assume.c b/test/c/special/assume.c index cb25eee4c..530ff3cea 100644 --- a/test/c/special/assume.c +++ b/test/c/special/assume.c @@ -4,9 +4,11 @@ // @flag --llvm-assumes=use int main(void) { - unsigned int y = 2 * (unsigned int)__VERIFIER_nondet_unsigned_short(); + unsigned int x = __VERIFIER_nondet_unsigned_int(); + unsigned int y = __VERIFIER_nondet_unsigned_int(); // This assumption is used for verification, even though // integer-encoding=bit-vector is not enabled, the assertion will pass. - __builtin_assume((y | 1) == (y + 1)); - assert((y | 1) == (y + 1)); + __builtin_assume((x ^ y) == (y ^ x)); + assert((x ^ y) == (y ^ x)); + return 0; } diff --git a/test/c/special/assume2.c b/test/c/special/assume2.c index 9df5ec7c8..4148c3f8a 100644 --- a/test/c/special/assume2.c +++ b/test/c/special/assume2.c @@ -4,9 +4,10 @@ // @flag --llvm-assumes=use int main(void) { - unsigned int y = (2 * (unsigned int)__VERIFIER_nondet_unsigned_short()) + 1; + unsigned int x = __VERIFIER_nondet_unsigned_int(); // This assumption is used for verification, even though the assumption // is false, the assertion will pass. - __builtin_assume((y | 1) == (y + 1)); - assert((y | 1) == (y + 1)); + __builtin_assume((x ^ x) == 1); + assert((x ^ x) == 1); + return 0; } diff --git a/test/c/special/assume_check.c b/test/c/special/assume_check.c index d1c2a37f8..709cc7b28 100644 --- a/test/c/special/assume_check.c +++ b/test/c/special/assume_check.c @@ -5,9 +5,11 @@ // @flag --integer-encoding=bit-vector int main(void) { - unsigned int y = 2 * (unsigned int)__VERIFIER_nondet_unsigned_short(); + unsigned int x = __VERIFIER_nondet_unsigned_int(); + unsigned int y = __VERIFIER_nondet_unsigned_int(); // This assumption is checked under integer-encoding=bit-vector and is // verified. - __builtin_assume((y & 1) == 0); - assert((y & 1) == 0); + __builtin_assume((x ^ y) == (y ^ x)); + assert((x ^ y) == (y ^ x)); + return 0; } diff --git a/test/c/special/assume_check2.c b/test/c/special/assume_check2.c index 9a98a02c6..431e30bdc 100644 --- a/test/c/special/assume_check2.c +++ b/test/c/special/assume_check2.c @@ -5,10 +5,10 @@ // @flag --integer-encoding=bit-vector int main(void) { - unsigned int y = (2 * (unsigned int)__VERIFIER_nondet_unsigned_short()) + 1; + unsigned int x = __VERIFIER_nondet_unsigned_int(); // This assumption is checked at verification time, and since - // integer-encoding=bit-vector is enabled, and y is clearly odd, the check - // will pass. - __builtin_assume((y & 1) == 1); - assert((y & 1) == 1); + // integer-encoding=bit-vector is enabled, the check will pass. + __builtin_assume((x ^ x) == 0); + assert((x ^ x) == 0); + return 0; } diff --git a/test/c/special/assume_check_fail.c b/test/c/special/assume_check_fail.c index 5abfcba79..a7fa947a3 100644 --- a/test/c/special/assume_check_fail.c +++ b/test/c/special/assume_check_fail.c @@ -5,10 +5,12 @@ // @flag --integer-encoding=bit-vector int main(void) { - unsigned int y = (2 * (unsigned int)__VERIFIER_nondet_unsigned_short()) + 1; + unsigned int x = __VERIFIER_nondet_unsigned_int(); + unsigned int y = __VERIFIER_nondet_unsigned_int(); // This assumption is checked at verification time, and since - // integer-encoding=bit-vector is enabled, and y is clearly odd, the - // assumption should be shown false. - __builtin_assume((y | 1) == (y + 1)); - assert((y | 1) == (y + 1)); + // integer-encoding=bit-vector is enabled, the assumption should + // be shown false. + __builtin_assume((x ^ y) != (y ^ x)); + assert((x ^ y) != (y ^ x)); + return 0; } diff --git a/test/c/special/assume_fail.c b/test/c/special/assume_fail.c index 5390efeb1..5c3744665 100644 --- a/test/c/special/assume_fail.c +++ b/test/c/special/assume_fail.c @@ -4,9 +4,11 @@ // @flag --llvm-assumes=none int main(void) { - unsigned int y = 2 * (unsigned int)__VERIFIER_nondet_unsigned_short(); + unsigned int x = __VERIFIER_nondet_unsigned_int(); + unsigned int y = __VERIFIER_nondet_unsigned_int(); // This assumption is not used, and since integer-encoding=bit-vector is // not enabled, verification will fail. - __builtin_assume((y | 1) == (y + 1)); - assert((y | 1) == (y + 1)); + __builtin_assume((x ^ y) == (y ^ x)); + assert((x ^ y) == (y ^ x)); + return 0; } From 71969b832d5496c26bda37a2ce5e515ad42cbaa7 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Tue, 10 Nov 2020 22:44:15 -0700 Subject: [PATCH 071/109] Fixed an issue with types on and and or procedure Now we try to match the bit-width of the original operation that we are replacing with a procedure call. --- lib/smack/RewriteBitwiseOps.cpp | 16 ++++++++++++++-- share/smack/lib/smack.c | 12 ++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/smack/RewriteBitwiseOps.cpp b/lib/smack/RewriteBitwiseOps.cpp index a79b832db..251d56bc8 100644 --- a/lib/smack/RewriteBitwiseOps.cpp +++ b/lib/smack/RewriteBitwiseOps.cpp @@ -101,7 +101,13 @@ bool RewriteBitwiseOps::runOnModule(Module &m) { // } if (maskOperand == -1) { - Function *co = m.getFunction("__SMACK_and"); + unsigned bitWidth = getOpBitWidth(&*I); + Function *co; + if (bitWidth == 64) { + co = m.getFunction("__SMACK_and64"); + } else { + co = m.getFunction("__SMACK_and32"); + } assert(co != NULL && "Function __SMACK_and should be present."); std::vector args; args.push_back(bi->getOperand(0)); @@ -118,7 +124,13 @@ bool RewriteBitwiseOps::runOnModule(Module &m) { instsTo.push_back(replacement); } } else if (opcode == Instruction::Or) { - Function *co = m.getFunction("__SMACK_or"); + unsigned bitWidth = getOpBitWidth(&*I); + Function *co; + if (bitWidth == 64) { + co = m.getFunction("__SMACK_or64"); + } else { + co = m.getFunction("__SMACK_or32"); + } assert(co != NULL && "Function __SMACK_or should be present."); std::vector args; args.push_back(bi->getOperand(0)); diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index c2185f713..28d50594b 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -83,8 +83,8 @@ EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long); EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long, int); #endif // RUST_EXEC -int __SMACK_and(int a, int b) { - int c = 0; +long __SMACK_and64(long a, long b) { + long c = 0; __VERIFIER_assume(a != 0 && b != 0); @@ -267,8 +267,10 @@ int __SMACK_and(int a, int b) { return c; } -int __SMACK_or(int a, int b) { - int c = 0; +int __SMACK_and32(int a, int b) { return (int)__SMACK_and64(a, b); } + +long __SMACK_or64(long a, long b) { + long c = 0; __VERIFIER_assume(a != 0 && b != 0); @@ -451,6 +453,8 @@ int __SMACK_or(int a, int b) { return c; } +int __SMACK_or32(int a, int b) { return (int)__SMACK_or64(a, b); } + void __SMACK_check_overflow(int flag) { __SMACK_dummy(flag); __SMACK_code("assert {:overflow} @ == $0;", flag); From a611d90c0e2684c3cd0441076eb99a3dc9c23107 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Wed, 11 Nov 2020 10:02:12 -0700 Subject: [PATCH 072/109] Made and and or procedures longer and 64 bit invokes 32 bit --- share/smack/lib/smack.c | 364 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 358 insertions(+), 6 deletions(-) diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index 28d50594b..a506d65a9 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -83,8 +83,8 @@ EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long); EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long, int); #endif // RUST_EXEC -long __SMACK_and64(long a, long b) { - long c = 0; +int __SMACK_and32(int a, int b) { + int c = 0; __VERIFIER_assume(a != 0 && b != 0); @@ -264,13 +264,189 @@ long __SMACK_and64(long a, long b) { b += b; b = b % 2147483648; + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + if (b < 0) { + c += 1; + } + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + return c; } -int __SMACK_and32(int a, int b) { return (int)__SMACK_and64(a, b); } +long __SMACK_and64(long a, long b) { return (long)__SMACK_and32(a, b); } -long __SMACK_or64(long a, long b) { - long c = 0; +int __SMACK_or32(int a, int b) { + int c = 0; __VERIFIER_assume(a != 0 && b != 0); @@ -450,10 +626,186 @@ long __SMACK_or64(long a, long b) { b += b; b = b % 2147483648; + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + + c += c; + if (a < 0) { + c += 1; + } else if (b < 0) { + c += 1; + } + a += a; + a = a % 2147483648; + b += b; + b = b % 2147483648; + return c; } -int __SMACK_or32(int a, int b) { return (int)__SMACK_or64(a, b); } +long __SMACK_or64(long a, long b) { return (long)__SMACK_or32(a, b); } void __SMACK_check_overflow(int flag) { __SMACK_dummy(flag); From e728bbbb241d681db317364184cad4f577200bc1 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Wed, 11 Nov 2020 12:07:15 -0700 Subject: [PATCH 073/109] Added support for 8 and 16 bit and and or procedures --- lib/smack/RewriteBitwiseOps.cpp | 8 ++++++++ share/smack/lib/smack.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/lib/smack/RewriteBitwiseOps.cpp b/lib/smack/RewriteBitwiseOps.cpp index 251d56bc8..4c7c74739 100644 --- a/lib/smack/RewriteBitwiseOps.cpp +++ b/lib/smack/RewriteBitwiseOps.cpp @@ -105,6 +105,10 @@ bool RewriteBitwiseOps::runOnModule(Module &m) { Function *co; if (bitWidth == 64) { co = m.getFunction("__SMACK_and64"); + } else if (bitWidth == 16) { + co = m.getFunction("__SMACK_and16"); + } else if (bitWidth == 8) { + co = m.getFunction("__SMACK_and8"); } else { co = m.getFunction("__SMACK_and32"); } @@ -128,6 +132,10 @@ bool RewriteBitwiseOps::runOnModule(Module &m) { Function *co; if (bitWidth == 64) { co = m.getFunction("__SMACK_or64"); + } else if (bitWidth == 16) { + co = m.getFunction("__SMACK_or16"); + } else if (bitWidth == 8) { + co = m.getFunction("__SMACK_or8"); } else { co = m.getFunction("__SMACK_or32"); } diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index a506d65a9..f41eb5bb0 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -444,6 +444,8 @@ int __SMACK_and32(int a, int b) { } long __SMACK_and64(long a, long b) { return (long)__SMACK_and32(a, b); } +short __SMACK_and16(short a, short b) { return (short)__SMACK_and32(a, b); } +char __SMACK_and8(char a, char b) { return (char)__SMACK_and32(a, b); } int __SMACK_or32(int a, int b) { int c = 0; @@ -806,6 +808,8 @@ int __SMACK_or32(int a, int b) { } long __SMACK_or64(long a, long b) { return (long)__SMACK_or32(a, b); } +short __SMACK_or16(short a, short b) { return (short)__SMACK_or32(a, b); } +char __SMACK_or8(char a, char b) { return (char)__SMACK_or32(a, b); } void __SMACK_check_overflow(int flag) { __SMACK_dummy(flag); From 8d3ac0e9cdd64e36f8f28d0b60b26116ae7d28b8 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Wed, 11 Nov 2020 16:40:22 -0700 Subject: [PATCH 074/109] Added rewrite-bitwise-ops command line option Now this pass is enabled only what that option is provided. We enable it by default for SVCOMP benchmarks, which have many bitwise ops. --- include/smack/SmackOptions.h | 1 + lib/smack/SmackOptions.cpp | 5 +++++ share/smack/svcomp/utils.py | 3 +++ share/smack/top.py | 9 +++++++++ test/c/special/bitwise_constant_shifts.c | 1 + test/c/special/bitwise_constant_shifts_fail.c | 1 + tools/llvm2bpl/llvm2bpl.cpp | 3 ++- 7 files changed, 22 insertions(+), 1 deletion(-) diff --git a/include/smack/SmackOptions.h b/include/smack/SmackOptions.h index 15aa72a7e..6e6e69149 100644 --- a/include/smack/SmackOptions.h +++ b/include/smack/SmackOptions.h @@ -25,6 +25,7 @@ class SmackOptions { static const llvm::cl::opt SourceLocSymbols; static llvm::cl::opt BitPrecise; static const llvm::cl::opt BitPrecisePointers; + static const llvm::cl::opt RewriteBitwiseOps; static const llvm::cl::opt NoMemoryRegionSplitting; static const llvm::cl::opt NoByteAccessInference; static const llvm::cl::opt FloatEnabled; diff --git a/lib/smack/SmackOptions.cpp b/lib/smack/SmackOptions.cpp index 295e397af..22f5f7a00 100644 --- a/lib/smack/SmackOptions.cpp +++ b/lib/smack/SmackOptions.cpp @@ -48,6 +48,11 @@ const llvm::cl::opt SmackOptions::AddTiming("timing-annotations", llvm::cl::desc("Add timing annotations.")); +const llvm::cl::opt SmackOptions::RewriteBitwiseOps( + "rewrite-bitwise-ops", + llvm::cl::desc( + "Provides models for bitwise operations in integer encoding.")); + const llvm::cl::opt SmackOptions::NoMemoryRegionSplitting( "no-memory-splitting", llvm::cl::desc("Disable splitting memory into regions.")); diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 20653d45f..013785951 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -14,6 +14,9 @@ def svcomp_frontend(input_file, args): # enable static LLVM unroll pass args.static_unroll = True + # attempt to rewrite bitwise ops into provided models + args.rewrite_bitwise_ops = True + # Modeling of strings must be turned on by default args.strings = True diff --git a/share/smack/top.py b/share/smack/top.py index 604f4b34b..a80726018 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -390,6 +390,13 @@ def arguments(): type=str, help='save (intermediate) Boogie code to FILE') + translate_group.add_argument( + '--rewrite-bitwise-ops', + action="store_true", + default=False, + help='''attempts to provide models for bitwise operations + when integer encoding is used''') + translate_group.add_argument( '--no-memory-splitting', action="store_true", @@ -716,6 +723,8 @@ def llvm_to_bpl(args): cmd += ['-bit-precise-pointers'] if args.no_byte_access_inference: cmd += ['-no-byte-access-inference'] + if args.rewrite_bitwise_ops: + cmd += ['-rewrite-bitwise-ops'] if args.no_memory_splitting: cmd += ['-no-memory-splitting'] if args.check.contains_mem_safe_props(): diff --git a/test/c/special/bitwise_constant_shifts.c b/test/c/special/bitwise_constant_shifts.c index b467b49d9..1dde15a10 100644 --- a/test/c/special/bitwise_constant_shifts.c +++ b/test/c/special/bitwise_constant_shifts.c @@ -1,6 +1,7 @@ #include "smack.h" // @expect verified +// @flag --rewrite-bitwise-ops int main(void) { unsigned char x = __VERIFIER_nondet_unsigned_char(); diff --git a/test/c/special/bitwise_constant_shifts_fail.c b/test/c/special/bitwise_constant_shifts_fail.c index fbc1834a0..c1378e87c 100644 --- a/test/c/special/bitwise_constant_shifts_fail.c +++ b/test/c/special/bitwise_constant_shifts_fail.c @@ -1,6 +1,7 @@ #include "smack.h" // @expect error +// @flag --rewrite-bitwise-ops int main(void) { unsigned char x = __VERIFIER_nondet_unsigned_char(); diff --git a/tools/llvm2bpl/llvm2bpl.cpp b/tools/llvm2bpl/llvm2bpl.cpp index 38f348c3d..85e1a5b37 100644 --- a/tools/llvm2bpl/llvm2bpl.cpp +++ b/tools/llvm2bpl/llvm2bpl.cpp @@ -196,7 +196,8 @@ int main(int argc, char **argv) { pass_manager.add(new smack::IntegerOverflowChecker()); - if (!(smack::SmackOptions::BitPrecise || + if (smack::SmackOptions::RewriteBitwiseOps && + !(smack::SmackOptions::BitPrecise || smack::SmackOptions::BitPrecisePointers)) { pass_manager.add(new smack::RewriteBitwiseOps()); } From 0a18828ba35e099e20174a73cd1bca8918597de4 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 11 Nov 2020 17:28:30 -0700 Subject: [PATCH 075/109] Model ctpop for integer encoding --- lib/smack/SmackInstGenerator.cpp | 31 ++++++++++++++++++++++--------- test/c/special/countpop8.c | 30 ++++++++++++++++++++++++++++++ test/c/special/countpop8_fail.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 test/c/special/countpop8.c create mode 100644 test/c/special/countpop8_fail.c diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index 16c002dd0..e21c830c6 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -1078,19 +1078,32 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { {&SmackOptions::BitPrecise}); // Count the population of 1s in a bv - static const auto ctpop = [this](Value *arg) { + static const auto ctpop = [this](CallInst *ci) { + Value *arg = ci->getArgOperand(0); auto width = arg->getType()->getIntegerBitWidth(); auto var = rep->expr(arg); - auto body = Expr::lit(0, width); + const Expr *body = nullptr; auto type = rep->type(arg->getType()); - for (unsigned i = 0; i < width; ++i) { - body = Expr::fn(indexedName("$add", {type}), - Expr::fn(indexedName("$zext", {"bv1", type}), - Expr::bvExtract(var, i + 1, i)), - body); + if (type.rfind("bv", 0) == 0) { // Bitvector mode + body = Expr::lit(0, width); + for (unsigned i = 0; i < width; ++i) { + body = Expr::fn(indexedName("$add", {type}), + Expr::fn(indexedName("$zext", {"bv1", type}), + Expr::bvExtract(var, i + 1, i)), + body); + } + } else { + body = Expr::lit(0ull); + for (unsigned i = 0; i < width; ++i) { + auto quotient = Expr::fn(indexedName("$udiv", {type}), var, + Expr::lit((unsigned long long)(1ull << i))); + auto remainder = + Expr::fn(indexedName("$urem", {type}), quotient, Expr::lit(2ull)); + body = Expr::fn(indexedName("$add", {type}), remainder, body); + } } - return body; + emit(Stmt::assign(rep->expr(ci), body)); }; static const auto assignBvExpr = @@ -1166,7 +1179,7 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { {llvm::Intrinsic::convert_from_fp16, f16UpCast}, {llvm::Intrinsic::convert_to_fp16, f16DownCast}, {llvm::Intrinsic::ctlz, ctlz}, - {llvm::Intrinsic::ctpop, assignBvExpr(ctpop)}, + {llvm::Intrinsic::ctpop, ctpop}, {llvm::Intrinsic::cttz, cttz}, {llvm::Intrinsic::dbg_declare, ignore}, {llvm::Intrinsic::dbg_label, ignore}, diff --git a/test/c/special/countpop8.c b/test/c/special/countpop8.c new file mode 100644 index 000000000..d8e3a7f75 --- /dev/null +++ b/test/c/special/countpop8.c @@ -0,0 +1,30 @@ +#include "smack.h" +#include + +// @expect verified + +uint8_t ctpop8(uint8_t x) { + uint8_t result = 0; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + return result; +} + +int main(void) { + uint8_t x = __VERIFIER_nondet_unsigned_char(); + assert(__builtin_popcount(x) == ctpop8(x)); + return 0; +} diff --git a/test/c/special/countpop8_fail.c b/test/c/special/countpop8_fail.c new file mode 100644 index 000000000..b22a6e0c0 --- /dev/null +++ b/test/c/special/countpop8_fail.c @@ -0,0 +1,30 @@ +#include "smack.h" +#include + +// @expect verified + +uint8_t ctpop8(uint8_t x) { + uint8_t result = 0; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + return result; +} + +int main(void) { + uint8_t x = __VERIFIER_nondet_unsigned_char(); + assert(__builtin_popcount(x) != ctpop8(x)); + return 0; +} From 2a108924021d3f2f8622f454ab21e0d555e9fc07 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 11 Nov 2020 18:30:10 -0700 Subject: [PATCH 076/109] Fix switching ctpop encoding mode --- lib/smack/SmackInstGenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index de51fe439..38a208f5b 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -1087,7 +1087,7 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { const Expr *body = nullptr; auto type = rep->type(arg->getType()); - if (type.rfind("bv", 0) == 0) { // Bitvector mode + if (SmackOptions::BitPrecise) { // Bitvector mode body = Expr::lit(0, width); for (unsigned i = 0; i < width; ++i) { body = Expr::fn(indexedName("$add", {type}), @@ -1095,7 +1095,7 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { Expr::bvExtract(var, i + 1, i)), body); } - } else { + } else { // Otherwise, try with the integer encoding body = Expr::lit(0ull); for (unsigned i = 0; i < width; ++i) { auto quotient = Expr::fn(indexedName("$udiv", {type}), var, From 868177ec6fd18908b71b790f5172c23704d8c6e2 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 11 Nov 2020 20:25:13 -0700 Subject: [PATCH 077/109] Fixed regression --- test/c/special/countpop8_fail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/c/special/countpop8_fail.c b/test/c/special/countpop8_fail.c index b22a6e0c0..323861a23 100644 --- a/test/c/special/countpop8_fail.c +++ b/test/c/special/countpop8_fail.c @@ -1,7 +1,7 @@ #include "smack.h" #include -// @expect verified +// @expect error uint8_t ctpop8(uint8_t x) { uint8_t result = 0; From 91ae19aec4b6b77552225111cddf439ce7f2016a Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Wed, 11 Nov 2020 21:56:31 -0700 Subject: [PATCH 078/109] Reduce regression difficulty --- test/c/special/countpop8.c | 1 + test/c/special/countpop8_fail.c | 1 + 2 files changed, 2 insertions(+) diff --git a/test/c/special/countpop8.c b/test/c/special/countpop8.c index d8e3a7f75..f5438a413 100644 --- a/test/c/special/countpop8.c +++ b/test/c/special/countpop8.c @@ -25,6 +25,7 @@ uint8_t ctpop8(uint8_t x) { int main(void) { uint8_t x = __VERIFIER_nondet_unsigned_char(); + __VERIFIER_assume(x < 32); assert(__builtin_popcount(x) == ctpop8(x)); return 0; } diff --git a/test/c/special/countpop8_fail.c b/test/c/special/countpop8_fail.c index 323861a23..0dec2195b 100644 --- a/test/c/special/countpop8_fail.c +++ b/test/c/special/countpop8_fail.c @@ -25,6 +25,7 @@ uint8_t ctpop8(uint8_t x) { int main(void) { uint8_t x = __VERIFIER_nondet_unsigned_char(); + __VERIFIER_assume(x < 32); assert(__builtin_popcount(x) != ctpop8(x)); return 0; } From 7b0688d141b5f5e4fafe11f51f2434a7776f1bfb Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Wed, 11 Nov 2020 22:05:25 -0700 Subject: [PATCH 079/109] Make warning system aware of flag relations --- include/smack/SmackWarnings.h | 18 ++++++--- lib/smack/SmackInstGenerator.cpp | 69 ++++++++++++++++++-------------- lib/smack/SmackWarnings.cpp | 40 +++++++++++------- 3 files changed, 76 insertions(+), 51 deletions(-) diff --git a/include/smack/SmackWarnings.h b/include/smack/SmackWarnings.h index 3713f925d..800d4f84d 100644 --- a/include/smack/SmackWarnings.h +++ b/include/smack/SmackWarnings.h @@ -26,22 +26,30 @@ class SmackWarnings { Info = 20 // Memory length, etc. }; + enum class FlagRelation : unsigned { And = 0, Or = 1 }; + static UnsetFlagsT getUnsetFlags(RequiredFlagsT flags); + static bool isSatisfied(RequiredFlagsT flags, FlagRelation rel); // generate warnings about unsoundness static void warnUnsound(std::string unmodeledOpName, Block *currBlock, - const llvm::Instruction *i, bool ignore = false); + const llvm::Instruction *i, bool ignore = false, + FlagRelation rel = FlagRelation::And); static void warnUnsound(std::string name, UnsetFlagsT unsetFlags, Block *currBlock, const llvm::Instruction *i, - bool ignore = false); + bool ignore = false, + FlagRelation rel = FlagRelation::And); static void warnIfUnsound(std::string name, RequiredFlagsT requiredFlags, Block *currBlock, const llvm::Instruction *i, - bool ignore = false); + bool ignore = false, + FlagRelation rel = FlagRelation::And); static void warnIfUnsound(std::string name, FlagT &requiredFlag, - Block *currBlock, const llvm::Instruction *i); + Block *currBlock, const llvm::Instruction *i, + FlagRelation rel = FlagRelation::And); static void warnIfUnsound(std::string name, FlagT &requiredFlag1, FlagT &requiredFlag2, Block *currBlock, - const llvm::Instruction *i); + const llvm::Instruction *i, + FlagRelation rel = FlagRelation::And); // generate warnings about memcpy/memset length/DSA static void warnInfo(std::string info); diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index 38a208f5b..ae7e9912b 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -898,15 +898,18 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { //(CallInst -> Void) -> [Flags] -> (CallInst -> Void) static const auto conditionalModel = [this](std::function modelGenFunc, - std::initializer_list *> requiredFlags) { + std::initializer_list *> requiredFlags, + SmackWarnings::FlagRelation rel = + SmackWarnings::FlagRelation::And) { auto unsetFlags = SmackWarnings::getUnsetFlags(requiredFlags); - return [this, unsetFlags, modelGenFunc](CallInst *ci) { - if (unsetFlags.empty()) + auto satisfied = SmackWarnings::isSatisfied(requiredFlags, rel); + return [this, unsetFlags, modelGenFunc, satisfied, rel](CallInst *ci) { + if (satisfied) modelGenFunc(ci); else { SmackWarnings::warnUnsound( "call to " + ci->getCalledFunction()->getName().str(), - unsetFlags, currBlock, ci); + unsetFlags, currBlock, ci, false, rel); emit(rep->call(ci->getCalledFunction(), *ci)); } }; @@ -1080,33 +1083,37 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { {&SmackOptions::BitPrecise}); // Count the population of 1s in a bv - static const auto ctpop = [this](CallInst *ci) { - Value *arg = ci->getArgOperand(0); - auto width = arg->getType()->getIntegerBitWidth(); - auto var = rep->expr(arg); - const Expr *body = nullptr; - auto type = rep->type(arg->getType()); - - if (SmackOptions::BitPrecise) { // Bitvector mode - body = Expr::lit(0, width); - for (unsigned i = 0; i < width; ++i) { - body = Expr::fn(indexedName("$add", {type}), - Expr::fn(indexedName("$zext", {"bv1", type}), - Expr::bvExtract(var, i + 1, i)), - body); - } - } else { // Otherwise, try with the integer encoding - body = Expr::lit(0ull); - for (unsigned i = 0; i < width; ++i) { - auto quotient = Expr::fn(indexedName("$udiv", {type}), var, - Expr::lit((unsigned long long)(1ull << i))); - auto remainder = - Expr::fn(indexedName("$urem", {type}), quotient, Expr::lit(2ull)); - body = Expr::fn(indexedName("$add", {type}), remainder, body); - } - } - emit(Stmt::assign(rep->expr(ci), body)); - }; + static const auto ctpop = conditionalModel( + [this](CallInst *ci) { + Value *arg = ci->getArgOperand(0); + auto width = arg->getType()->getIntegerBitWidth(); + auto var = rep->expr(arg); + const Expr *body = nullptr; + auto type = rep->type(arg->getType()); + + if (SmackOptions::BitPrecise) { // Bitvector mode + body = Expr::lit(0, width); + for (unsigned i = 0; i < width; ++i) { + body = Expr::fn(indexedName("$add", {type}), + Expr::fn(indexedName("$zext", {"bv1", type}), + Expr::bvExtract(var, i + 1, i)), + body); + } + } else { // Otherwise, try with the integer encoding + body = Expr::lit(0ull); + for (unsigned i = 0; i < width; ++i) { + auto quotient = + Expr::fn(indexedName("$udiv", {type}), var, + Expr::lit((unsigned long long)(1ull << i))); + auto remainder = Expr::fn(indexedName("$urem", {type}), quotient, + Expr::lit(2ull)); + body = Expr::fn(indexedName("$add", {type}), remainder, body); + } + } + emit(Stmt::assign(rep->expr(ci), body)); + }, + {&SmackOptions::BitPrecise, &SmackOptions::RewriteBitwiseOps}, + SmackWarnings::FlagRelation::Or); static const auto assignBvExpr = [this](std::function exprGenFunc) { diff --git a/lib/smack/SmackWarnings.cpp b/lib/smack/SmackWarnings.cpp index b7bc2b1cd..a6c22243e 100644 --- a/lib/smack/SmackWarnings.cpp +++ b/lib/smack/SmackWarnings.cpp @@ -36,35 +36,42 @@ SmackWarnings::getUnsetFlags(RequiredFlagsT requiredFlags) { return ret; } +bool SmackWarnings::isSatisfied(RequiredFlagsT requiredFlags, + FlagRelation rel) { + auto unsetFlags = getUnsetFlags(requiredFlags); + return rel == FlagRelation::And ? unsetFlags.empty() + : unsetFlags.size() < requiredFlags.size(); +} + std::string SmackWarnings::getFlagStr(UnsetFlagsT flags) { - std::string ret = ""; + std::string ret = "{ "; for (auto f : flags) { if (f->ArgStr.str() == "bit-precise") ret += ("--integer-encoding=bit-vector "); else ret += ("--" + f->ArgStr.str() + " "); } - return ret; + return ret + "}"; } void SmackWarnings::warnIfUnsound(std::string name, RequiredFlagsT requiredFlags, Block *currBlock, const Instruction *i, - bool ignore) { - auto unsetFlags = getUnsetFlags(requiredFlags); - if (unsetFlags.size()) - warnUnsound(name, unsetFlags, currBlock, i, ignore); + bool ignore, FlagRelation rel) { + if (!isSatisfied(requiredFlags, rel)) + warnUnsound(name, getUnsetFlags(requiredFlags), currBlock, i, ignore); } void SmackWarnings::warnUnsound(std::string unmodeledOpName, Block *currBlock, - const Instruction *i, bool ignore) { + const Instruction *i, bool ignore, + FlagRelation rel) { warnUnsound("unmodeled operation " + unmodeledOpName, UnsetFlagsT(), - currBlock, i, ignore); + currBlock, i, ignore, rel); } void SmackWarnings::warnUnsound(std::string name, UnsetFlagsT unsetFlags, Block *currBlock, const Instruction *i, - bool ignore) { + bool ignore, FlagRelation rel) { if (!isSufficientWarningLevel(WarningLevel::Unsound)) return; std::string beginning = std::string("llvm2bpl: ") + buildDebugInfo(i); @@ -73,8 +80,9 @@ void SmackWarnings::warnUnsound(std::string name, UnsetFlagsT unsetFlags, if (currBlock) currBlock->addStmt(Stmt::comment(beginning + "warning: " + end)); std::string hint = ""; - if (unsetFlags.size()) - hint = (" try adding flag(s): " + getFlagStr(unsetFlags)); + if (!unsetFlags.empty()) + hint = (" try adding " + ((rel == FlagRelation::And ? "all the " : "any ") + + ("flag(s) in: " + getFlagStr(unsetFlags)))); errs() << beginning; (SmackOptions::ColoredWarnings ? errs().changeColor(raw_ostream::MAGENTA) : errs()) @@ -84,14 +92,16 @@ void SmackWarnings::warnUnsound(std::string name, UnsetFlagsT unsetFlags, } void SmackWarnings::warnIfUnsound(std::string name, FlagT &requiredFlag, - Block *currBlock, const Instruction *i) { - warnIfUnsound(name, {&requiredFlag}, currBlock, i); + Block *currBlock, const Instruction *i, + FlagRelation rel) { + warnIfUnsound(name, {&requiredFlag}, currBlock, i, false, rel); } void SmackWarnings::warnIfUnsound(std::string name, FlagT &requiredFlag1, FlagT &requiredFlag2, Block *currBlock, - const Instruction *i) { - warnIfUnsound(name, {&requiredFlag1, &requiredFlag2}, currBlock, i); + const Instruction *i, FlagRelation rel) { + warnIfUnsound(name, {&requiredFlag1, &requiredFlag2}, currBlock, i, false, + rel); } void SmackWarnings::warnInfo(std::string info) { From 214c7e85f38761e228becf975ac64e4615926cfb Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Wed, 11 Nov 2020 23:09:20 -0700 Subject: [PATCH 080/109] Fixed regressions --- test/c/special/countpop8.c | 1 + test/c/special/countpop8_fail.c | 1 + 2 files changed, 2 insertions(+) diff --git a/test/c/special/countpop8.c b/test/c/special/countpop8.c index f5438a413..ae31f0cc0 100644 --- a/test/c/special/countpop8.c +++ b/test/c/special/countpop8.c @@ -1,6 +1,7 @@ #include "smack.h" #include +// @flag --rewrite-bitwise-ops // @expect verified uint8_t ctpop8(uint8_t x) { diff --git a/test/c/special/countpop8_fail.c b/test/c/special/countpop8_fail.c index 0dec2195b..0fbebb9b8 100644 --- a/test/c/special/countpop8_fail.c +++ b/test/c/special/countpop8_fail.c @@ -1,6 +1,7 @@ #include "smack.h" #include +// @flag --rewrite-bitwise-ops // @expect error uint8_t ctpop8(uint8_t x) { From 3f1a2de68a2225b003c4bc69b7a655d2d13d291c Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Thu, 12 Nov 2020 00:27:38 -0700 Subject: [PATCH 081/109] Fixed regressions --- test/c/special/countpop8.c | 35 ++++++++++++++------------------- test/c/special/countpop8_fail.c | 35 ++++++++++++++------------------- 2 files changed, 30 insertions(+), 40 deletions(-) diff --git a/test/c/special/countpop8.c b/test/c/special/countpop8.c index ae31f0cc0..1aa0266dd 100644 --- a/test/c/special/countpop8.c +++ b/test/c/special/countpop8.c @@ -4,29 +4,24 @@ // @flag --rewrite-bitwise-ops // @expect verified -uint8_t ctpop8(uint8_t x) { - uint8_t result = 0; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - return result; -} +uint8_t results[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, + 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, + 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; + +uint8_t ctpop8(uint8_t x) { return results[x]; } int main(void) { uint8_t x = __VERIFIER_nondet_unsigned_char(); - __VERIFIER_assume(x < 32); + __VERIFIER_assume(x > 251 && x <= 255); assert(__builtin_popcount(x) == ctpop8(x)); return 0; } diff --git a/test/c/special/countpop8_fail.c b/test/c/special/countpop8_fail.c index 0fbebb9b8..4f085ed3e 100644 --- a/test/c/special/countpop8_fail.c +++ b/test/c/special/countpop8_fail.c @@ -4,29 +4,24 @@ // @flag --rewrite-bitwise-ops // @expect error -uint8_t ctpop8(uint8_t x) { - uint8_t result = 0; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - return result; -} +uint8_t results[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, + 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, + 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; + +uint8_t ctpop8(uint8_t x) { return results[x]; } int main(void) { uint8_t x = __VERIFIER_nondet_unsigned_char(); - __VERIFIER_assume(x < 32); + __VERIFIER_assume(x > 251 && x <= 255); assert(__builtin_popcount(x) != ctpop8(x)); return 0; } From 4078ee7bb5fc0b67a531c4634fde28717bafe883 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Thu, 12 Nov 2020 08:55:34 -0700 Subject: [PATCH 082/109] unsigned->signed --- lib/smack/SmackInstGenerator.cpp | 4 ++-- test/c/special/countpop8.c | 34 ++++++++++++++++++-------------- test/c/special/countpop8_fail.c | 34 ++++++++++++++++++-------------- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index ae7e9912b..30523bf17 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -1103,9 +1103,9 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { body = Expr::lit(0ull); for (unsigned i = 0; i < width; ++i) { auto quotient = - Expr::fn(indexedName("$udiv", {type}), var, + Expr::fn(indexedName("$sdiv", {type}), var, Expr::lit((unsigned long long)(1ull << i))); - auto remainder = Expr::fn(indexedName("$urem", {type}), quotient, + auto remainder = Expr::fn(indexedName("$srem", {type}), quotient, Expr::lit(2ull)); body = Expr::fn(indexedName("$add", {type}), remainder, body); } diff --git a/test/c/special/countpop8.c b/test/c/special/countpop8.c index 1aa0266dd..ba8d9d0ae 100644 --- a/test/c/special/countpop8.c +++ b/test/c/special/countpop8.c @@ -4,24 +4,28 @@ // @flag --rewrite-bitwise-ops // @expect verified -uint8_t results[256] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, - 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, - 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, - 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, - 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, - 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; - -uint8_t ctpop8(uint8_t x) { return results[x]; } +uint8_t ctpop8(uint8_t x) { + uint8_t result = 0; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + return result; +} int main(void) { uint8_t x = __VERIFIER_nondet_unsigned_char(); - __VERIFIER_assume(x > 251 && x <= 255); assert(__builtin_popcount(x) == ctpop8(x)); return 0; } diff --git a/test/c/special/countpop8_fail.c b/test/c/special/countpop8_fail.c index 4f085ed3e..7754ea274 100644 --- a/test/c/special/countpop8_fail.c +++ b/test/c/special/countpop8_fail.c @@ -4,24 +4,28 @@ // @flag --rewrite-bitwise-ops // @expect error -uint8_t results[256] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, - 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, - 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, - 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, - 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, - 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; - -uint8_t ctpop8(uint8_t x) { return results[x]; } +uint8_t ctpop8(uint8_t x) { + uint8_t result = 0; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + x /= 2; + result += x % 2; + return result; +} int main(void) { uint8_t x = __VERIFIER_nondet_unsigned_char(); - __VERIFIER_assume(x > 251 && x <= 255); assert(__builtin_popcount(x) != ctpop8(x)); return 0; } From edade9d99fda3872fa719dc9797adc621a9cc72e Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Thu, 12 Nov 2020 10:55:13 -0700 Subject: [PATCH 083/109] Revert "unsigned->signed" This reverts commit 4078ee7bb5fc0b67a531c4634fde28717bafe883. --- lib/smack/SmackInstGenerator.cpp | 4 ++-- test/c/special/countpop8.c | 34 ++++++++++++++------------------ test/c/special/countpop8_fail.c | 34 ++++++++++++++------------------ 3 files changed, 32 insertions(+), 40 deletions(-) diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index 30523bf17..ae7e9912b 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -1103,9 +1103,9 @@ void SmackInstGenerator::visitIntrinsicInst(llvm::IntrinsicInst &ii) { body = Expr::lit(0ull); for (unsigned i = 0; i < width; ++i) { auto quotient = - Expr::fn(indexedName("$sdiv", {type}), var, + Expr::fn(indexedName("$udiv", {type}), var, Expr::lit((unsigned long long)(1ull << i))); - auto remainder = Expr::fn(indexedName("$srem", {type}), quotient, + auto remainder = Expr::fn(indexedName("$urem", {type}), quotient, Expr::lit(2ull)); body = Expr::fn(indexedName("$add", {type}), remainder, body); } diff --git a/test/c/special/countpop8.c b/test/c/special/countpop8.c index ba8d9d0ae..1aa0266dd 100644 --- a/test/c/special/countpop8.c +++ b/test/c/special/countpop8.c @@ -4,28 +4,24 @@ // @flag --rewrite-bitwise-ops // @expect verified -uint8_t ctpop8(uint8_t x) { - uint8_t result = 0; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - return result; -} +uint8_t results[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, + 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, + 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; + +uint8_t ctpop8(uint8_t x) { return results[x]; } int main(void) { uint8_t x = __VERIFIER_nondet_unsigned_char(); + __VERIFIER_assume(x > 251 && x <= 255); assert(__builtin_popcount(x) == ctpop8(x)); return 0; } diff --git a/test/c/special/countpop8_fail.c b/test/c/special/countpop8_fail.c index 7754ea274..4f085ed3e 100644 --- a/test/c/special/countpop8_fail.c +++ b/test/c/special/countpop8_fail.c @@ -4,28 +4,24 @@ // @flag --rewrite-bitwise-ops // @expect error -uint8_t ctpop8(uint8_t x) { - uint8_t result = 0; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - x /= 2; - result += x % 2; - return result; -} +uint8_t results[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, + 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, + 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; + +uint8_t ctpop8(uint8_t x) { return results[x]; } int main(void) { uint8_t x = __VERIFIER_nondet_unsigned_char(); + __VERIFIER_assume(x > 251 && x <= 255); assert(__builtin_popcount(x) != ctpop8(x)); return 0; } From 3a0dfa437285f87541a8f3cface1ca81a3d86e86 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Thu, 12 Nov 2020 14:22:07 -0700 Subject: [PATCH 084/109] Use assert and assume instead of __VERIFIER prefixed versions This is making our regressions more uniform. --- test/c/failing/bitwise_and.c | 37 ++++++++++--------- test/c/failing/bitwise_and_fail.c | 3 +- .../pthread_extras/dekker_true-unreach-call.c | 2 +- .../pthread_extras/sigma_false-unreach-call.c | 4 +- .../sigma_false_GREAT-unreach-call.c | 4 +- .../pthread_extras/sssc12_true-unreach-call.c | 2 +- .../time_var_mutex_true-unreach-call.c | 2 +- test/c/special/bitwise_constant_shifts.c | 33 +++++++++-------- test/c/special/bitwise_constant_shifts_fail.c | 3 +- test/c/special/countpop8.c | 2 +- test/c/special/countpop8_fail.c | 2 +- 11 files changed, 49 insertions(+), 45 deletions(-) diff --git a/test/c/failing/bitwise_and.c b/test/c/failing/bitwise_and.c index 2198021ed..b7591ae79 100644 --- a/test/c/failing/bitwise_and.c +++ b/test/c/failing/bitwise_and.c @@ -5,39 +5,40 @@ int main(void) { unsigned char x = (unsigned char)__VERIFIER_nondet_unsigned_char(); { // y = 0 - __VERIFIER_assert((x & 0) == (x % (0 + 1))); - __VERIFIER_assert((0 & x) == (x % (0 + 1))); + assert((x & 0) == (x % (0 + 1))); + assert((0 & x) == (x % (0 + 1))); } { // y = 1 - __VERIFIER_assert((x & 1) == (x % (1 + 1))); - __VERIFIER_assert((1 & x) == (x % (1 + 1))); + assert((x & 1) == (x % (1 + 1))); + assert((1 & x) == (x % (1 + 1))); } { // y = 3 - __VERIFIER_assert((x & 3) == (x % (3 + 1))); - __VERIFIER_assert((3 & x) == (x % (3 + 1))); + assert((x & 3) == (x % (3 + 1))); + assert((3 & x) == (x % (3 + 1))); } { // y = 7 - __VERIFIER_assert((x & 7) == (x % (7 + 1))); - __VERIFIER_assert((7 & x) == (x % (7 + 1))); + assert((x & 7) == (x % (7 + 1))); + assert((7 & x) == (x % (7 + 1))); } { // y = 15 - __VERIFIER_assert((x & 15) == (x % (15 + 1))); - __VERIFIER_assert((15 & x) == (x % (15 + 1))); + assert((x & 15) == (x % (15 + 1))); + assert((15 & x) == (x % (15 + 1))); } { // y = 31 - __VERIFIER_assert((x & 31) == (x % (31 + 1))); - __VERIFIER_assert((31 & x) == (x % (31 + 1))); + assert((x & 31) == (x % (31 + 1))); + assert((31 & x) == (x % (31 + 1))); } { // y = 63 - __VERIFIER_assert((x & 63) == (x % (63 + 1))); - __VERIFIER_assert((63 & x) == (x % (63 + 1))); + assert((x & 63) == (x % (63 + 1))); + assert((63 & x) == (x % (63 + 1))); } { // y = 127 - __VERIFIER_assert((x & 127) == (x % (127 + 1))); - __VERIFIER_assert((127 & x) == (x % (127 + 1))); + assert((x & 127) == (x % (127 + 1))); + assert((127 & x) == (x % (127 + 1))); } { // y = 255 - __VERIFIER_assert((x & 255) == x); - __VERIFIER_assert((255 & x) == x); + assert((x & 255) == x); + assert((255 & x) == x); } + return 0; } diff --git a/test/c/failing/bitwise_and_fail.c b/test/c/failing/bitwise_and_fail.c index 4aa0f5415..e42e4e31f 100644 --- a/test/c/failing/bitwise_and_fail.c +++ b/test/c/failing/bitwise_and_fail.c @@ -41,5 +41,6 @@ int main(void) { cond = cond || ((x & 255) != x); cond = cond || ((255 & x) != x); } - __VERIFIER_assert(cond); + assert(cond); + return 0; } diff --git a/test/c/pthread_extras/dekker_true-unreach-call.c b/test/c/pthread_extras/dekker_true-unreach-call.c index b26f12292..b98d24c3a 100644 --- a/test/c/pthread_extras/dekker_true-unreach-call.c +++ b/test/c/pthread_extras/dekker_true-unreach-call.c @@ -50,7 +50,7 @@ void *thr2(void *arg) { int main() { pthread_t t1, t2; - __VERIFIER_assume(0 <= turn && turn <= 1); + assume(0 <= turn && turn <= 1); pthread_create(&t1, 0, thr1, 0); pthread_create(&t2, 0, thr2, 0); pthread_join(t1, 0); diff --git a/test/c/pthread_extras/sigma_false-unreach-call.c b/test/c/pthread_extras/sigma_false-unreach-call.c index de1a09643..c7a692723 100644 --- a/test/c/pthread_extras/sigma_false-unreach-call.c +++ b/test/c/pthread_extras/sigma_false-unreach-call.c @@ -23,8 +23,8 @@ int main() { t = (pthread_t *)malloc(sizeof(pthread_t) * SIGMA); array = (int *)malloc(sizeof(int) * SIGMA); - //__VERIFIER_assume(t); - //__VERIFIER_assume(array); + // assume(t); + // assume(array); for (tid = 0; tid < SIGMA; tid++) { pthread_create(&t[tid], 0, thread, 0); diff --git a/test/c/pthread_extras/sigma_false_GREAT-unreach-call.c b/test/c/pthread_extras/sigma_false_GREAT-unreach-call.c index e4e4bcb8d..1ec417155 100644 --- a/test/c/pthread_extras/sigma_false_GREAT-unreach-call.c +++ b/test/c/pthread_extras/sigma_false_GREAT-unreach-call.c @@ -36,8 +36,8 @@ int main() { t = (pthread_t *)malloc(sizeof(pthread_t) * SIGMA); array = (int *)malloc(sizeof(int) * SIGMA); - //__VERIFIER_assume(t); - //__VERIFIER_assume(array); + // assume(t); + // assume(array); for (tid = 0; tid < SIGMA; tid++) { pthread_mutex_lock(&lock); diff --git a/test/c/pthread_extras/sssc12_true-unreach-call.c b/test/c/pthread_extras/sssc12_true-unreach-call.c index 994a64fd3..26cae599a 100644 --- a/test/c/pthread_extras/sssc12_true-unreach-call.c +++ b/test/c/pthread_extras/sssc12_true-unreach-call.c @@ -34,7 +34,7 @@ void main() { pthread_t t; next = 0; len = __VERIFIER_nondet_int(); - __VERIFIER_assume(len > 0); + assume(len > 0); data = malloc(sizeof(int) * len); while (1) { pthread_create(&t, 0, thr, 0); diff --git a/test/c/pthread_extras/time_var_mutex_true-unreach-call.c b/test/c/pthread_extras/time_var_mutex_true-unreach-call.c index 2e6237be5..4d94cd18e 100644 --- a/test/c/pthread_extras/time_var_mutex_true-unreach-call.c +++ b/test/c/pthread_extras/time_var_mutex_true-unreach-call.c @@ -44,7 +44,7 @@ void *de_allocator(void *arg) { int main() { pthread_t t1, t2; - __VERIFIER_assume(inode == busy); + assume(inode == busy); pthread_mutex_init(&m_inode, 0); pthread_mutex_init(&m_busy, 0); pthread_create(&t1, 0, allocator, 0); diff --git a/test/c/special/bitwise_constant_shifts.c b/test/c/special/bitwise_constant_shifts.c index 1dde15a10..8b1e9433a 100644 --- a/test/c/special/bitwise_constant_shifts.c +++ b/test/c/special/bitwise_constant_shifts.c @@ -6,36 +6,37 @@ int main(void) { unsigned char x = __VERIFIER_nondet_unsigned_char(); { // y = 0 - __VERIFIER_assert((x >> 0) == (x / 1)); - __VERIFIER_assert((x << 0) == (x * 1)); + assert((x >> 0) == (x / 1)); + assert((x << 0) == (x * 1)); } { // y = 1 - __VERIFIER_assert((x >> 1) == (x / 2)); - __VERIFIER_assert((x << 1) == (x * 2)); + assert((x >> 1) == (x / 2)); + assert((x << 1) == (x * 2)); } { // y = 3 - __VERIFIER_assert((x >> 3) == (x / 8)); - __VERIFIER_assert((x << 3) == (x * 8)); + assert((x >> 3) == (x / 8)); + assert((x << 3) == (x * 8)); } { // y = 4 - __VERIFIER_assert((x >> 4) == (x / 16)); - __VERIFIER_assert((x << 4) == (x * 16)); + assert((x >> 4) == (x / 16)); + assert((x << 4) == (x * 16)); } { // y = 5 - __VERIFIER_assert((x >> 5) == (x / 32)); - __VERIFIER_assert((x << 5) == (x * 32)); + assert((x >> 5) == (x / 32)); + assert((x << 5) == (x * 32)); } { // y = 6 - __VERIFIER_assert((x >> 6) == (x / 64)); - __VERIFIER_assert((x << 6) == (x * 64)); + assert((x >> 6) == (x / 64)); + assert((x << 6) == (x * 64)); } { // y = 7 - __VERIFIER_assert((x >> 7) == (x / 128)); - __VERIFIER_assert((x << 7) == (x * 128)); + assert((x >> 7) == (x / 128)); + assert((x << 7) == (x * 128)); } { // y = 8 - __VERIFIER_assert((x >> 8) == 0); + assert((x >> 8) == 0); // This may not be possible to handle correctly. - __VERIFIER_assert((x << 8) == x * 128 + x * 128); + assert((x << 8) == x * 128 + x * 128); } + return 0; } diff --git a/test/c/special/bitwise_constant_shifts_fail.c b/test/c/special/bitwise_constant_shifts_fail.c index c1378e87c..ed11f16de 100644 --- a/test/c/special/bitwise_constant_shifts_fail.c +++ b/test/c/special/bitwise_constant_shifts_fail.c @@ -39,5 +39,6 @@ int main(void) { // This may not be possible to handle correctly. cond = cond || ((x << 8) != x * 128 + x * 128); } - __VERIFIER_assert(cond); + assert(cond); + return 0; } diff --git a/test/c/special/countpop8.c b/test/c/special/countpop8.c index 1aa0266dd..5ba59a24a 100644 --- a/test/c/special/countpop8.c +++ b/test/c/special/countpop8.c @@ -21,7 +21,7 @@ uint8_t ctpop8(uint8_t x) { return results[x]; } int main(void) { uint8_t x = __VERIFIER_nondet_unsigned_char(); - __VERIFIER_assume(x > 251 && x <= 255); + assume(x > 251 && x <= 255); assert(__builtin_popcount(x) == ctpop8(x)); return 0; } diff --git a/test/c/special/countpop8_fail.c b/test/c/special/countpop8_fail.c index 4f085ed3e..1868415d3 100644 --- a/test/c/special/countpop8_fail.c +++ b/test/c/special/countpop8_fail.c @@ -21,7 +21,7 @@ uint8_t ctpop8(uint8_t x) { return results[x]; } int main(void) { uint8_t x = __VERIFIER_nondet_unsigned_char(); - __VERIFIER_assume(x > 251 && x <= 255); + assume(x > 251 && x <= 255); assert(__builtin_popcount(x) != ctpop8(x)); return 0; } From a7b27e5bb220c222409b57c7c07c6e79c85916b8 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Thu, 12 Nov 2020 17:40:11 -0700 Subject: [PATCH 085/109] Temporarily fixed LLVM intrinsics modeling This commit always enables precise modeling of the overflow flag and does not inject blocking assumes. --- lib/smack/IntegerOverflowChecker.cpp | 55 +++++++++++----------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/lib/smack/IntegerOverflowChecker.cpp b/lib/smack/IntegerOverflowChecker.cpp index 0d1679596..5b92cb3aa 100644 --- a/lib/smack/IntegerOverflowChecker.cpp +++ b/lib/smack/IntegerOverflowChecker.cpp @@ -52,15 +52,12 @@ std::string IntegerOverflowChecker::getMin(unsigned bits, bool isSigned) { */ Value *IntegerOverflowChecker::extendBitWidth(Value *v, int bits, bool isSigned, Instruction *i) { - if (SmackOptions::IntegerOverflow) { - if (isSigned) - return CastInst::CreateSExtOrBitCast( - v, IntegerType::get(i->getFunction()->getContext(), bits * 2), "", i); - else - return CastInst::CreateZExtOrBitCast( - v, IntegerType::get(i->getFunction()->getContext(), bits * 2), "", i); - } else - return v; + if (isSigned) + return CastInst::CreateSExtOrBitCast( + v, IntegerType::get(i->getFunction()->getContext(), bits * 2), "", i); + else + return CastInst::CreateZExtOrBitCast( + v, IntegerType::get(i->getFunction()->getContext(), bits * 2), "", i); } /* @@ -70,24 +67,19 @@ Value *IntegerOverflowChecker::extendBitWidth(Value *v, int bits, bool isSigned, BinaryOperator *IntegerOverflowChecker::createFlag(Value *v, int bits, bool isSigned, Instruction *i) { - if (SmackOptions::IntegerOverflow) { - ConstantInt *max = ConstantInt::get( - IntegerType::get(i->getFunction()->getContext(), bits * 2), - getMax(bits, isSigned), 10); - ConstantInt *min = ConstantInt::get( - IntegerType::get(i->getFunction()->getContext(), bits * 2), - getMin(bits, isSigned), 10); - CmpInst::Predicate maxCmpPred = - (isSigned ? CmpInst::ICMP_SGT : CmpInst::ICMP_UGT); - CmpInst::Predicate minCmpPred = - (isSigned ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT); - ICmpInst *gt = new ICmpInst(i, maxCmpPred, v, max, ""); - ICmpInst *lt = new ICmpInst(i, minCmpPred, v, min, ""); - return BinaryOperator::Create(Instruction::Or, gt, lt, "", i); - } else { - ConstantInt *a = ConstantInt::getFalse(i->getFunction()->getContext()); - return BinaryOperator::Create(Instruction::And, a, a, "", i); - } + ConstantInt *max = ConstantInt::get( + IntegerType::get(i->getFunction()->getContext(), bits * 2), + getMax(bits, isSigned), 10); + ConstantInt *min = ConstantInt::get( + IntegerType::get(i->getFunction()->getContext(), bits * 2), + getMin(bits, isSigned), 10); + CmpInst::Predicate maxCmpPred = + (isSigned ? CmpInst::ICMP_SGT : CmpInst::ICMP_UGT); + CmpInst::Predicate minCmpPred = + (isSigned ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT); + ICmpInst *gt = new ICmpInst(i, maxCmpPred, v, max, ""); + ICmpInst *lt = new ICmpInst(i, minCmpPred, v, min, ""); + return BinaryOperator::Create(Instruction::Or, gt, lt, "", i); } /* @@ -95,11 +87,8 @@ BinaryOperator *IntegerOverflowChecker::createFlag(Value *v, int bits, */ Value *IntegerOverflowChecker::createResult(Value *v, int bits, Instruction *i) { - if (SmackOptions::IntegerOverflow) - return CastInst::CreateTruncOrBitCast( - v, IntegerType::get(i->getFunction()->getContext(), bits), "", i); - else - return v; + return CastInst::CreateTruncOrBitCast( + v, IntegerType::get(i->getFunction()->getContext(), bits), "", i); } /* @@ -196,7 +185,7 @@ bool IntegerOverflowChecker::runOnModule(Module &m) { ei->replaceAllUsesWith(r); else if (ei->getIndices()[0] == 1) { // flag part - addBlockingAssume(va, flag, ei); + // addBlockingAssume(va, flag, ei); ei->replaceAllUsesWith(flag); } else llvm_unreachable("Unexpected extractvalue inst!"); From 83505f8ad446814b744a7d01d970bc0e1619d87a Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 13 Nov 2020 13:41:50 -0700 Subject: [PATCH 086/109] Do not rewrite bitwise ops when bitwidth is 1 We are handling these precisely using axioms. --- lib/smack/RewriteBitwiseOps.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/smack/RewriteBitwiseOps.cpp b/lib/smack/RewriteBitwiseOps.cpp index 4c7c74739..63f558baa 100644 --- a/lib/smack/RewriteBitwiseOps.cpp +++ b/lib/smack/RewriteBitwiseOps.cpp @@ -78,8 +78,7 @@ bool RewriteBitwiseOps::runOnModule(Module &m) { instsFrom.push_back(&*I); instsTo.push_back(replacement); } - } - if (I->isBitwiseLogicOp()) { + } else if (I->isBitwiseLogicOp()) { // If the operation is a bit-wise `and' and the mask variable is // constant, it may be possible to replace this operation with a // remainder operation. If one argument has only ones, and they're only @@ -109,6 +108,8 @@ bool RewriteBitwiseOps::runOnModule(Module &m) { co = m.getFunction("__SMACK_and16"); } else if (bitWidth == 8) { co = m.getFunction("__SMACK_and8"); + } else if (bitWidth == 1) { + continue; } else { co = m.getFunction("__SMACK_and32"); } @@ -136,6 +137,8 @@ bool RewriteBitwiseOps::runOnModule(Module &m) { co = m.getFunction("__SMACK_or16"); } else if (bitWidth == 8) { co = m.getFunction("__SMACK_or8"); + } else if (bitWidth == 1) { + continue; } else { co = m.getFunction("__SMACK_or32"); } From 55737ca2537716691edf66926f7bc431cfb020a1 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Fri, 13 Nov 2020 14:12:49 -0700 Subject: [PATCH 087/109] Do not emit warnings about bitwise operations of bit-width 1 We have precisely modeled them using axioms. --- lib/smack/SmackInstGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index ae7e9912b..e3584b15c 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -351,7 +351,7 @@ void SmackInstGenerator::visitUnreachableInst(llvm::UnreachableInst &ii) { void SmackInstGenerator::visitBinaryOperator(llvm::BinaryOperator &I) { processInstruction(I); - if (rep->isBitwiseOp(&I)) + if (rep->isBitwiseOp(&I) && I.getType()->getIntegerBitWidth() > 1) SmackWarnings::warnIfUnsound(std::string("bitwise operation ") + I.getOpcodeName(), SmackOptions::BitPrecise, currBlock, &I); From 483355bcac160ca4d48f00496441e3486bc8b26d Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 13 Nov 2020 14:52:39 -0700 Subject: [PATCH 088/109] Sub binary operation should be treated as unsigned --- lib/smack/SmackRep.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/smack/SmackRep.cpp b/lib/smack/SmackRep.cpp index d961d9533..1d21bbe64 100644 --- a/lib/smack/SmackRep.cpp +++ b/lib/smack/SmackRep.cpp @@ -926,7 +926,8 @@ const Expr *SmackRep::bop(unsigned opcode, const llvm::Value *lhs, if (opcode == llvm::Instruction::SDiv || opcode == llvm::Instruction::SRem) { isUnsigned = false; } else if (opcode == llvm::Instruction::UDiv || - opcode == llvm::Instruction::URem) { + opcode == llvm::Instruction::URem || + opcode == llvm::Instruction::Sub) { isUnsigned = true; } @@ -939,8 +940,8 @@ const Expr *SmackRep::bop(unsigned opcode, const llvm::Value *lhs, return Expr::fn(opName(fn, {t}), expr(lhs), expr(rhs)); } } - return Expr::fn(opName(fn, {t}), expr(lhs, isUnsigned), - expr(rhs, isUnsigned)); + return Expr::fn(opName(fn, {t}), expr(lhs, isUnsigned, opcode == llvm::Instruction::Sub), + expr(rhs, isUnsigned, opcode == llvm::Instruction::Sub)); } const Expr *SmackRep::uop(const llvm::ConstantExpr *CE) { From 4552a2d94e37f952256ef51cb00fdde4f1e225ec Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 13 Nov 2020 14:56:16 -0700 Subject: [PATCH 089/109] Added model for __builtin_expect function --- share/smack/lib/smack.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index f41eb5bb0..84e546d09 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -38,6 +38,10 @@ void *__builtinx_va_arg(char *x) { return 0; } +long __builtin_expect(long exp, long c) { + return exp; +} + void __VERIFIER_assume(int x) { #if !RUST_EXEC __SMACK_dummy(x); From ad3d3ac0c0d457f3c3259ce2987fa3428c5e85eb Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Fri, 13 Nov 2020 15:40:32 -0700 Subject: [PATCH 090/109] Moved error trace handling into a designated Python file --- share/smack/errtrace.py | 200 ++++++++++++++++++++++++++++++++++++ share/smack/svcomp/utils.py | 3 +- share/smack/top.py | 184 +-------------------------------- 3 files changed, 203 insertions(+), 184 deletions(-) create mode 100644 share/smack/errtrace.py diff --git a/share/smack/errtrace.py b/share/smack/errtrace.py new file mode 100644 index 000000000..f5ea305e5 --- /dev/null +++ b/share/smack/errtrace.py @@ -0,0 +1,200 @@ +import re +import functools +import shutil +import subprocess +import json + + +def reformat_assignment(line): + '''Transform assignment RHS values''' + + def repl(m): + val = m.group(1) + if 'bv' in val: + return m.group(2) + 'UL' + else: + sig_size = int(m.group(7)) + exp_size = int(m.group(8)) + # assume we can only handle double + if sig_size > 53 or exp_size > 11: + return m.group() + + sign_val = -1 if m.group(3) != '' else 1 + sig_val = m.group(4) + exp_sign_val = -1 if m.group(5) != '' else 1 + # note that the exponent base is 16 + exp_val = 2**(4 * exp_sign_val * int(m.group(6))) + return str(sign_val * float.fromhex(sig_val) * exp_val) + + # Boogie FP const grammar: (-)0x[sig]e[exp]f[sigSize]e[expSize], where + # sig = hexdigit {hexdigit} '.' hexdigit {hexdigit} + # exp = digit {digit} + # sigSize = digit {digit} + # expSize = digit {digit} + return re.sub( + (r'((\d+)bv\d+|(-?)0x([0-9a-fA-F]+\.[0-9a-fA-F]+)e(-?)' + r'(\d+)f(\d+)e(\d+))'), + repl, + line.strip()) + + +def demangle(func): + '''Demangle C++/Rust function names''' + + def demangle_with(func, tool): + if shutil.which(tool): + p = subprocess.Popen( + tool, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, _ = p.communicate(input=func.encode()) + return out.decode() + return func + return functools.reduce(demangle_with, ['cxxfilt', 'rustfilt'], func) + + +def transform(info): + '''Transform an error trace line''' + + info = info.strip() + if info.startswith('CALL') or info.startswith('RETURN from'): + tokens = info.split() + tokens[-1] = demangle(tokens[-1]) + return ' '.join(tokens) + elif '=' in info: + tokens = info.split('=') + lhs = tokens[0].strip() + rhs = tokens[1].strip() + return demangle(lhs) + ' = ' + reformat_assignment(rhs) + else: + return info + + +def corral_error_step(step): + '''Produce an error trace step based on a line of Corral error trace''' + + m = re.match(r'([^\s]*)\s+Trace:\s+(Thread=\d+)\s+\((.*)[\)|;]', step) + if m: + path = m.group(1) + tid = m.group(2) + info = ','.join(map(transform, + [x for x in m.group(3).split(',') if not + re.search( + (r'((CALL|RETURN from)\s+(\$|__SMACK))|' + r'Done|ASSERTION'), x)])) + return '{0}\t{1} {2}'.format(path, tid, info) + else: + return step + + +def error_step(step): + '''Produce an error trace step based on a line of verifier output''' + + FILENAME = r'[\w#$~%.\/-]*' + step = re.match(r"(\s*)(%s)\((\d+),\d+\): (.*)" % FILENAME, step) + if step: + if re.match('.*[.]bpl$', step.group(2)): + line_no = int(step.group(3)) + message = step.group(4) + if re.match(r'.*\$bb\d+.*', message): + message = "" + with open(step.group(2)) as f: + for line in f.read().splitlines(True)[line_no:line_no + 10]: + src = re.match( + r".*{:sourceloc \"(%s)\", (\d+), (\d+)}" % + FILENAME, line) + if src: + return "%s%s(%s,%s): %s" % (step.group(1), src.group( + 1), src.group(2), src.group(3), message) + else: + return corral_error_step(step.group(0)) + else: + return None + + +def error_trace(verifier_output, args): + '''Generate string error trace.''' + + trace = "" + for line in verifier_output.splitlines(True): + step = error_step(line) + if step: + m = re.match('(.*): [Ee]rror [A-Z0-9]+: (.*)', step) + if m: + trace += "%s: %s\nExecution trace:\n" % ( + m.group(1), m.group(2)) + else: + trace += ('' if step[0] == ' ' else ' ') + step + "\n" + + return trace + + +def smackdOutput(corralOutput): + '''Convert error traces into JSON format''' + + FILENAME = r'[\w#$~%.\/-]+' + traceP = re.compile( + ('(' + + FILENAME + + r')\((\d+),(\d+)\): Trace: Thread=(\d+)(\((.*)[\);])?$')) + errorP = re.compile('(' + FILENAME + r')\((\d+),(\d+)\): (error .*)$') + + passedMatch = re.search('Program has no bugs', corralOutput) + if passedMatch: + json_data = { + 'verifier': 'corral', + 'passed?': True + } + + else: + traces = [] + filename = '' + lineno = 0 + colno = 0 + threadid = 0 + desc = '' + for traceLine in corralOutput.splitlines(True): + traceMatch = traceP.match(traceLine) + if traceMatch: + filename = str(traceMatch.group(1)) + lineno = int(traceMatch.group(2)) + colno = int(traceMatch.group(3)) + threadid = int(traceMatch.group(4)) + desc = str(traceMatch.group(6)) + for e in desc.split(','): + e = e.strip() + assm = re.sub( + r'=(\s*\d+)bv\d+', + r'=\1', + e) if '=' in e else '' + trace = {'threadid': threadid, + 'file': filename, + 'line': lineno, + 'column': colno, + 'description': e, + 'assumption': assm} + traces.append(trace) + else: + errorMatch = errorP.match(traceLine) + if errorMatch: + filename = str(errorMatch.group(1)) + lineno = int(errorMatch.group(2)) + colno = int(errorMatch.group(3)) + desc = str(errorMatch.group(4)) + + failsAt = { + 'file': filename, + 'line': lineno, + 'column': colno, + 'description': desc} + + json_data = { + 'verifier': 'corral', + 'passed?': False, + 'failsAt': failsAt, + 'threadCount': 1, + 'traces': traces + } + json_string = json.dumps(json_data) + return json_string diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 013785951..8a1c45080 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -175,6 +175,7 @@ def verify_bpl_svcomp(args): def write_error_file(args, status, verifier_output): from smack.top import VProperty from smack.top import VResult + from smack.errtrace import smackdOutput #return if status is VResult.VERIFIED or status is VResult.UNKNOWN: return @@ -184,7 +185,7 @@ def write_error_file(args, status, verifier_output): if args.error_file: error = None if args.language == 'svcomp': - error = smackJsonToXmlGraph(smack.top.smackdOutput(verifier_output), args, hasBug, status) + error = smackJsonToXmlGraph(smackdOutput(verifier_output), args, hasBug, status) elif hasBug: error = smack.top.error_trace(verifier_output, args) if error is not None: diff --git a/share/smack/top.py b/share/smack/top.py index a80726018..12013c4df 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -1,8 +1,6 @@ import argparse -import json import os import re -import shutil import sys import shlex import subprocess @@ -13,6 +11,7 @@ from .utils import temporary_file, try_command, remove_temp_files from .replay import replay_error_trace from .frontend import link_bc_files, frontends, languages, extra_libs +from .errtrace import error_trace, smackdOutput VERSION = '2.6.0' @@ -932,187 +931,6 @@ def verify_bpl(args): sys.exit(result.return_code()) -def error_step(step): - FILENAME = r'[\w#$~%.\/-]*' - step = re.match(r"(\s*)(%s)\((\d+),\d+\): (.*)" % FILENAME, step) - if step: - if re.match('.*[.]bpl$', step.group(2)): - line_no = int(step.group(3)) - message = step.group(4) - if re.match(r'.*\$bb\d+.*', message): - message = "" - with open(step.group(2)) as f: - for line in f.read().splitlines(True)[line_no:line_no + 10]: - src = re.match( - r".*{:sourceloc \"(%s)\", (\d+), (\d+)}" % - FILENAME, line) - if src: - return "%s%s(%s,%s): %s" % (step.group(1), src.group( - 1), src.group(2), src.group(3), message) - else: - return corral_error_step(step.group(0)) - else: - return None - - -def reformat_assignment(line): - def repl(m): - val = m.group(1) - if 'bv' in val: - return m.group(2) + 'UL' - else: - sig_size = int(m.group(7)) - exp_size = int(m.group(8)) - # assume we can only handle double - if sig_size > 53 or exp_size > 11: - return m.group() - - sign_val = -1 if m.group(3) != '' else 1 - sig_val = m.group(4) - exp_sign_val = -1 if m.group(5) != '' else 1 - # note that the exponent base is 16 - exp_val = 2**(4 * exp_sign_val * int(m.group(6))) - return str(sign_val * float.fromhex(sig_val) * exp_val) - - # Boogie FP const grammar: (-)0x[sig]e[exp]f[sigSize]e[expSize], where - # sig = hexdigit {hexdigit} '.' hexdigit {hexdigit} - # exp = digit {digit} - # sigSize = digit {digit} - # expSize = digit {digit} - return re.sub( - (r'((\d+)bv\d+|(-?)0x([0-9a-fA-F]+\.[0-9a-fA-F]+)e(-?)' - r'(\d+)f(\d+)e(\d+))'), - repl, - line.strip()) - - -def demangle(func): - def demangle_with(func, tool): - if shutil.which(tool): - p = subprocess.Popen( - tool, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out, _ = p.communicate(input=func.encode()) - return out.decode() - return func - return functools.reduce(demangle_with, ['cxxfilt', 'rustfilt'], func) - - -def transform(info): - info = info.strip() - if info.startswith('CALL') or info.startswith('RETURN from'): - tokens = info.split() - tokens[-1] = demangle(tokens[-1]) - return ' '.join(tokens) - elif '=' in info: - tokens = info.split('=') - lhs = tokens[0].strip() - rhs = tokens[1].strip() - return demangle(lhs) + ' = ' + reformat_assignment(rhs) - else: - return info - - -def corral_error_step(step): - m = re.match(r'([^\s]*)\s+Trace:\s+(Thread=\d+)\s+\((.*)[\)|;]', step) - if m: - path = m.group(1) - tid = m.group(2) - info = ','.join(map(transform, - [x for x in m.group(3).split(',') if not - re.search( - (r'((CALL|RETURN from)\s+(\$|__SMACK))|' - r'Done|ASSERTION'), x)])) - return '{0}\t{1} {2}'.format(path, tid, info) - else: - return step - - -def error_trace(verifier_output, args): - trace = "" - for line in verifier_output.splitlines(True): - step = error_step(line) - if step: - m = re.match('(.*): [Ee]rror [A-Z0-9]+: (.*)', step) - if m: - trace += "%s: %s\nExecution trace:\n" % ( - m.group(1), m.group(2)) - else: - trace += ('' if step[0] == ' ' else ' ') + step + "\n" - - return trace - - -def smackdOutput(corralOutput): - FILENAME = r'[\w#$~%.\/-]+' - traceP = re.compile( - ('(' - + FILENAME - + r')\((\d+),(\d+)\): Trace: Thread=(\d+)(\((.*)[\);])?$')) - errorP = re.compile('(' + FILENAME + r')\((\d+),(\d+)\): (error .*)$') - - passedMatch = re.search('Program has no bugs', corralOutput) - if passedMatch: - json_data = { - 'verifier': 'corral', - 'passed?': True - } - - else: - traces = [] - filename = '' - lineno = 0 - colno = 0 - threadid = 0 - desc = '' - for traceLine in corralOutput.splitlines(True): - traceMatch = traceP.match(traceLine) - if traceMatch: - filename = str(traceMatch.group(1)) - lineno = int(traceMatch.group(2)) - colno = int(traceMatch.group(3)) - threadid = int(traceMatch.group(4)) - desc = str(traceMatch.group(6)) - for e in desc.split(','): - e = e.strip() - assm = re.sub( - r'=(\s*\d+)bv\d+', - r'=\1', - e) if '=' in e else '' - trace = {'threadid': threadid, - 'file': filename, - 'line': lineno, - 'column': colno, - 'description': e, - 'assumption': assm} - traces.append(trace) - else: - errorMatch = errorP.match(traceLine) - if errorMatch: - filename = str(errorMatch.group(1)) - lineno = int(errorMatch.group(2)) - colno = int(errorMatch.group(3)) - desc = str(errorMatch.group(4)) - - failsAt = { - 'file': filename, - 'line': lineno, - 'column': colno, - 'description': desc} - - json_data = { - 'verifier': 'corral', - 'passed?': False, - 'failsAt': failsAt, - 'threadCount': 1, - 'traces': traces - } - json_string = json.dumps(json_data) - return json_string - - def clean_up_upon_sigterm(main): def handler(signum, frame): remove_temp_files() From e8f6b3b8a47d8320c68125b9f772389c5bc4a99e Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Fri, 13 Nov 2020 18:56:24 -0700 Subject: [PATCH 091/109] Fixed JSON output generation as well as SV-COMP witnesses --- share/smack/errtrace.py | 30 ++++++++++++++++++++++++++---- share/smack/svcomp/utils.py | 2 +- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/share/smack/errtrace.py b/share/smack/errtrace.py index f5ea305e5..f550d7480 100644 --- a/share/smack/errtrace.py +++ b/share/smack/errtrace.py @@ -137,8 +137,8 @@ def smackdOutput(corralOutput): traceP = re.compile( ('(' + FILENAME - + r')\((\d+),(\d+)\): Trace: Thread=(\d+)(\((.*)[\);])?$')) - errorP = re.compile('(' + FILENAME + r')\((\d+),(\d+)\): (error .*)$') + + r')\((\d+),(\d+)\): Trace: Thread=(\d+)\s+\((.*(;\n)?.*)\)')) + errorP = re.compile('(' + FILENAME + r')\((\d+),(\d+)\): (error .*)') passedMatch = re.search('Program has no bugs', corralOutput) if passedMatch: @@ -149,7 +149,23 @@ def smackdOutput(corralOutput): else: traces = [] - filename = '' + raw_data = re.findall(traceP, corralOutput) + for t in raw_data: + file_name = t[0] + line_num = t[1] + col_num = t[2] + thread_id = t[3] + description = t[4] + for token in description.split(','): + traces.append( + {'threadid': thread_id, + 'file': file_name, + 'line': line_num, + 'column': col_num, + 'description': token, + 'assumption': transform(token) if '=' in token else ''}) + + r"""filename = '' lineno = 0 colno = 0 threadid = 0 @@ -181,7 +197,13 @@ def smackdOutput(corralOutput): filename = str(errorMatch.group(1)) lineno = int(errorMatch.group(2)) colno = int(errorMatch.group(3)) - desc = str(errorMatch.group(4)) + desc = str(errorMatch.group(4))""" + errorMatch = errorP.search(corralOutput) + assert(errorMatch) + filename = str(errorMatch.group(1)) + lineno = int(errorMatch.group(2)) + colno = int(errorMatch.group(3)) + desc = str(errorMatch.group(4)) failsAt = { 'file': filename, diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 8a1c45080..4cf857c8d 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -177,7 +177,7 @@ def write_error_file(args, status, verifier_output): from smack.top import VResult from smack.errtrace import smackdOutput #return - if status is VResult.VERIFIED or status is VResult.UNKNOWN: + if status is VResult.UNKNOWN: return hasBug = (status is not VResult.VERIFIED) #if not hasBug: From 7c2570db24ccad4ab26a8baf3d23152fc927472e Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 13 Nov 2020 19:04:27 -0700 Subject: [PATCH 092/109] Select instruction generates unsigned integer constants --- lib/smack/SmackRep.cpp | 7 +++++-- share/smack/lib/smack.c | 4 +--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/smack/SmackRep.cpp b/lib/smack/SmackRep.cpp index 1d21bbe64..3d5b7f9e8 100644 --- a/lib/smack/SmackRep.cpp +++ b/lib/smack/SmackRep.cpp @@ -940,7 +940,8 @@ const Expr *SmackRep::bop(unsigned opcode, const llvm::Value *lhs, return Expr::fn(opName(fn, {t}), expr(lhs), expr(rhs)); } } - return Expr::fn(opName(fn, {t}), expr(lhs, isUnsigned, opcode == llvm::Instruction::Sub), + return Expr::fn(opName(fn, {t}), + expr(lhs, isUnsigned, opcode == llvm::Instruction::Sub), expr(rhs, isUnsigned, opcode == llvm::Instruction::Sub)); } @@ -991,7 +992,9 @@ const Expr *SmackRep::select(const llvm::ConstantExpr *CE) { const Expr *SmackRep::select(const llvm::Value *condVal, const llvm::Value *trueVal, const llvm::Value *falseVal) { - const Expr *c = expr(condVal), *v1 = expr(trueVal), *v2 = expr(falseVal); + const Expr *c = expr(condVal); + const Expr *v1 = expr(trueVal, true, true); + const Expr *v2 = expr(falseVal, true, true); assert(!condVal->getType()->isVectorTy() && "Vector condition is not supported."); diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index 84e546d09..734bd2d4a 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -38,9 +38,7 @@ void *__builtinx_va_arg(char *x) { return 0; } -long __builtin_expect(long exp, long c) { - return exp; -} +long __builtin_expect(long exp, long c) { return exp; } void __VERIFIER_assume(int x) { #if !RUST_EXEC From f09907af405ab7aaa33794ac07f25b3c4f7486a8 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 13 Nov 2020 20:45:07 -0700 Subject: [PATCH 093/109] Constants passed to unsigned division should be treated as unsign --- lib/smack/SmackRep.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/smack/SmackRep.cpp b/lib/smack/SmackRep.cpp index 3d5b7f9e8..580d3b596 100644 --- a/lib/smack/SmackRep.cpp +++ b/lib/smack/SmackRep.cpp @@ -923,14 +923,6 @@ const Expr *SmackRep::bop(const llvm::BinaryOperator *BO) { const Expr *SmackRep::bop(unsigned opcode, const llvm::Value *lhs, const llvm::Value *rhs, const llvm::Type *t, bool isUnsigned) { - if (opcode == llvm::Instruction::SDiv || opcode == llvm::Instruction::SRem) { - isUnsigned = false; - } else if (opcode == llvm::Instruction::UDiv || - opcode == llvm::Instruction::URem || - opcode == llvm::Instruction::Sub) { - isUnsigned = true; - } - std::string fn = Naming::INSTRUCTION_TABLE.at(opcode); if (isFpArithOp(opcode)) { if (SmackOptions::FloatEnabled) { @@ -940,9 +932,20 @@ const Expr *SmackRep::bop(unsigned opcode, const llvm::Value *lhs, return Expr::fn(opName(fn, {t}), expr(lhs), expr(rhs)); } } + + bool isUnsignedInst = false; + if (opcode == llvm::Instruction::SDiv || opcode == llvm::Instruction::SRem) { + isUnsigned = false; + } else if (opcode == llvm::Instruction::UDiv || + opcode == llvm::Instruction::URem || + opcode == llvm::Instruction::Sub) { + isUnsignedInst = true; + isUnsigned = true; + } + return Expr::fn(opName(fn, {t}), - expr(lhs, isUnsigned, opcode == llvm::Instruction::Sub), - expr(rhs, isUnsigned, opcode == llvm::Instruction::Sub)); + expr(lhs, isUnsigned, isUnsignedInst), + expr(rhs, isUnsigned, isUnsignedInst)); } const Expr *SmackRep::uop(const llvm::ConstantExpr *CE) { From 379f52ca10580844272e6d6ded9f2c1654f49740 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sat, 14 Nov 2020 10:03:49 -0700 Subject: [PATCH 094/109] Fixed formatting and renamed an argument The argument isCmpInst is now inUnsignedInst since it captures more than just compare instructions. --- include/smack/SmackRep.h | 4 ++-- lib/smack/SmackRep.cpp | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/smack/SmackRep.h b/include/smack/SmackRep.h index b39048053..499930e6a 100644 --- a/include/smack/SmackRep.h +++ b/include/smack/SmackRep.h @@ -130,7 +130,7 @@ class SmackRep { std::string type(const llvm::Value *v); const Expr *lit(const llvm::Value *v, bool isUnsigned = false, - bool isCmpInst = false); + bool isUnsignedInst = false); const Expr *lit(const llvm::Value *v, unsigned flag); const Expr *ptrArith(const llvm::GetElementPtrInst *I); @@ -140,7 +140,7 @@ class SmackRep { std::vector> args); const Expr *expr(const llvm::Value *v, bool isConstIntUnsigned = false, - bool isCmpInst = false); + bool isUnsignedInst = false); const Expr *cast(const llvm::Instruction *I); const Expr *cast(const llvm::ConstantExpr *CE); diff --git a/lib/smack/SmackRep.cpp b/lib/smack/SmackRep.cpp index 580d3b596..998966787 100644 --- a/lib/smack/SmackRep.cpp +++ b/lib/smack/SmackRep.cpp @@ -625,7 +625,7 @@ const Expr *SmackRep::integerLit(long long v, unsigned width) { } const Expr *SmackRep::lit(const llvm::Value *v, bool isUnsigned, - bool isCmpInst) { + bool isUnsignedInst) { using namespace llvm; if (const ConstantInt *ci = llvm::dyn_cast(v)) { @@ -638,7 +638,7 @@ const Expr *SmackRep::lit(const llvm::Value *v, bool isUnsigned, // gets translated into i + (-1), and so in that context it should // be a signed integer. bool neg = width > 1 && - (isUnsigned ? (isCmpInst ? false : API.getSExtValue() == -1) + (isUnsigned ? (isUnsignedInst ? false : API.getSExtValue() == -1) : ci->isNegative()); std::string str = (neg ? API.abs() : API).toString(10, false); const Expr *e = @@ -794,7 +794,7 @@ const Expr *SmackRep::ptrArith( } const Expr *SmackRep::expr(const llvm::Value *v, bool isConstIntUnsigned, - bool isCmpInst) { + bool isUnsignedInst) { using namespace llvm; if (isa(v)) { @@ -837,7 +837,7 @@ const Expr *SmackRep::expr(const llvm::Value *v, bool isConstIntUnsigned, } } else if (const ConstantInt *ci = dyn_cast(constant)) { - return lit(ci, isConstIntUnsigned, isCmpInst); + return lit(ci, isConstIntUnsigned, isUnsignedInst); } else if (const ConstantFP *cf = dyn_cast(constant)) { return lit(cf); @@ -943,8 +943,7 @@ const Expr *SmackRep::bop(unsigned opcode, const llvm::Value *lhs, isUnsigned = true; } - return Expr::fn(opName(fn, {t}), - expr(lhs, isUnsigned, isUnsignedInst), + return Expr::fn(opName(fn, {t}), expr(lhs, isUnsigned, isUnsignedInst), expr(rhs, isUnsigned, isUnsignedInst)); } From 01e591fbd1eb21f2d1d2b9908b6e31da8cebacca Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sat, 14 Nov 2020 10:10:57 -0700 Subject: [PATCH 095/109] Turned __builtin_expect into a macro that rewrites it The macro rewrites it into __builtinx_expect, and I provide a model for that procedure. Otherwise, we have name clashes with other headers when running on regressions. --- share/smack/include/smack.h | 1 + share/smack/lib/smack.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/share/smack/include/smack.h b/share/smack/include/smack.h index cd29d2465..856e9e66c 100644 --- a/share/smack/include/smack.h +++ b/share/smack/include/smack.h @@ -21,6 +21,7 @@ extern "C" { #define __builtin_va_start __builtinx_va_start #define __builtin_va_arg(ap, t) __builtinx_va_arg(ap) #define __builtin_object_size __builtinx_object_size +#define __builtin_expect __builtinx_expect // For handling of va macros void __builtinx_va_start(char *, char *); diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index 734bd2d4a..0a6019ac7 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -38,7 +38,7 @@ void *__builtinx_va_arg(char *x) { return 0; } -long __builtin_expect(long exp, long c) { return exp; } +long __builtinx_expect(long exp, long c) { return exp; } void __VERIFIER_assume(int x) { #if !RUST_EXEC From e643d91ea2172033bb106f3f786cab6dc0a26abf Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Sat, 14 Nov 2020 16:26:52 -0700 Subject: [PATCH 096/109] Fixes 1. SMACK library info should not show up. 2. Assertion violation line number should not be the line where __VERIFIER_assert is called. --- share/smack/svcomp/toSVCOMPformat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/smack/svcomp/toSVCOMPformat.py b/share/smack/svcomp/toSVCOMPformat.py index d9fe441d2..562627641 100644 --- a/share/smack/svcomp/toSVCOMPformat.py +++ b/share/smack/svcomp/toSVCOMPformat.py @@ -153,7 +153,7 @@ def smackJsonToXmlGraph(strJsonOutput, args, hasBug, status): lastNode = start lastEdge = None - pat = re.compile(".*smack\.[c|h]$") + pat = re.compile(".*/smack/lib/.+\.[c|h]$") prevLineNo = -1 prevColNo = -1 callStack = [('main', '0')] @@ -167,7 +167,7 @@ def smackJsonToXmlGraph(strJsonOutput, args, hasBug, status): for vNode in vNodes: if vNode.attrib["id"] == newNode: addKey(vNode, "violation", "true") - attribs = {"startline":str(callStack[-1][1])} + attribs = {"startline":str(jsonViolation['line'])} addGraphEdge(tree, lastNode, newNode, attribs) break if not pat.match(jsonTrace["file"]): From bc5aacdb3fd89aacb36f85f5175bb4a84553bd1a Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Tue, 17 Nov 2020 15:02:16 -0700 Subject: [PATCH 097/109] Removed assumes from models of and and or bitwise procedures --- share/smack/lib/smack.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index 0a6019ac7..c9f1cc9de 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -88,8 +88,6 @@ EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long, int); int __SMACK_and32(int a, int b) { int c = 0; - __VERIFIER_assume(a != 0 && b != 0); - c += c; if (a < 0) { if (b < 0) { @@ -452,8 +450,6 @@ char __SMACK_and8(char a, char b) { return (char)__SMACK_and32(a, b); } int __SMACK_or32(int a, int b) { int c = 0; - __VERIFIER_assume(a != 0 && b != 0); - c += c; if (a < 0) { c += 1; From 0ac26f9b61ba17c805a290280dff62a1deb451cd Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Wed, 18 Nov 2020 22:43:40 -0700 Subject: [PATCH 098/109] Only enable assumption keys with return values of nondet functions --- share/smack/svcomp/toSVCOMPformat.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/share/smack/svcomp/toSVCOMPformat.py b/share/smack/svcomp/toSVCOMPformat.py index 562627641..346ccbef5 100644 --- a/share/smack/svcomp/toSVCOMPformat.py +++ b/share/smack/svcomp/toSVCOMPformat.py @@ -30,6 +30,7 @@ def addKeyDefs(root): #keys are [attr.name, attr.type, for, id, hasDefault, defaultVal] keys.append(["assumption", "string", "edge", "assumption", False]) keys.append(["assumption.scope", "string", "edge", "assumption.scope", False]) + keys.append(["assumption.resultfunction", "string", "edge", "assumption.resultfunction", False]) keys.append(["sourcecode", "string", "edge", "sourcecode", False]) keys.append(["witness-type", "string", "graph", "witness-type", False]) keys.append(["sourcecodeLanguage", "string", "graph", "sourcecodelang", False]) @@ -174,12 +175,18 @@ def smackJsonToXmlGraph(strJsonOutput, args, hasBug, status): desc = jsonTrace["description"] formattedAssign = formatAssign(desc) # Make sure it is not return value - if formattedAssign and not ":" in formattedAssign: + if formattedAssign and formattedAssign.startswith('smack:ext:__VERIFIER_nondet'): + tokens = formattedAssign.split('==') + nondet_func = tokens[0].strip()[len('smack:ext:'):] + val = tokens[1].strip() + new_assumption = '\\result == %s;' % val # Create new node and edge newNode = addGraphNode(tree) attribs = {"startline":str(jsonTrace["line"])} - attribs["assumption"] = formattedAssign + ";" - attribs["assumption.scope"] = callStack[-1][0] + attribs["assumption"] = new_assumption + attribs['assumption.resultfunction'] = nondet_func + scope_func = callStack[-1][0] + attribs["assumption.scope"] = scope_func.split('.')[0] if '.' in scope_func else scope_func newEdge = addGraphEdge(tree, lastNode, newNode, attribs) prevLineNo = jsonTrace["line"] prevColNo = jsonTrace["column"] From c188fef8cfb11ef626e5579caabe1843e41027bb Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 2 Nov 2020 19:15:02 -0700 Subject: [PATCH 099/109] Fixes for cargo builds --- CMakeLists.txt | 13 ++++--- examples/rust-cargo/Cargo.toml | 2 +- share/smack/frontend.py | 2 +- share/smack/include/smack.h | 5 --- share/smack/lib/smack-rust.c | 49 +++++++++++++++++++++++++++ share/smack/lib/smack.c | 33 +----------------- share/smack/lib/smack.rs | 36 ++++++++++---------- share/smack/lib/smack/build.rs | 6 ++-- test/rust/cargo/cargo-test/Cargo.toml | 2 +- 9 files changed, 83 insertions(+), 65 deletions(-) create mode 100644 share/smack/lib/smack-rust.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 287516b98..90c1d6b9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,13 +217,18 @@ INSTALL(FILES ) INSTALL(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/share/smack/include/smack.h - ${CMAKE_CURRENT_SOURCE_DIR}/share/smack/lib/smack.c - DESTINATION share/smack/smack/src + ${CMAKE_CURRENT_SOURCE_DIR}/share/smack/lib/smack/Cargo.toml + ${CMAKE_CURRENT_SOURCE_DIR}/share/smack/lib/smack/build.rs + DESTINATION share/smack/lib +) + +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/share/smack/lib/smack-rust.c + DESTINATION share/smack/lib/src ) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/share/smack/lib/smack.rs - DESTINATION share/smack/smack/src + DESTINATION share/smack/lib/src RENAME lib.rs ) diff --git a/examples/rust-cargo/Cargo.toml b/examples/rust-cargo/Cargo.toml index 164489e7f..1371b96e6 100644 --- a/examples/rust-cargo/Cargo.toml +++ b/examples/rust-cargo/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -smack = { path = "/usr/local/share/smack/lib/smack" } +smack = { path = "/usr/local/share/smack/lib" } [profile.dev] incremental=false diff --git a/share/smack/frontend.py b/share/smack/frontend.py index bdb492fdd..417646c97 100644 --- a/share/smack/frontend.py +++ b/share/smack/frontend.py @@ -367,7 +367,7 @@ def rust_frontend(input_file, args): def default_build_libs(args): """Generate LLVM bitcodes for SMACK libraries.""" bitcodes = [] - libs = ['smack.c', 'stdlib.c', 'errno.c'] + libs = ['smack.c', 'stdlib.c', 'errno.c', 'smack-rust.c'] if args.pthread: libs += ['pthread.c'] diff --git a/share/smack/include/smack.h b/share/smack/include/smack.h index 856e9e66c..2255b9864 100644 --- a/share/smack/include/smack.h +++ b/share/smack/include/smack.h @@ -87,11 +87,6 @@ void __VERIFIER_assert(int); #define U(...) TY(__VA_ARGS__, U4, U3, U2, U1)(__VA_ARGS__) #define NONDET_DECL(P, ty...) S(ty) U(P, U(ty))(void) -#define EMPTY_NONDET_DEFN(P, ty...) \ - S(ty) U(P, U(ty))(void) { \ - ty x; \ - return x; \ - } void *__VERIFIER_nondet(void); NONDET_DECL(__SMACK_nondet, char); diff --git a/share/smack/lib/smack-rust.c b/share/smack/lib/smack-rust.c new file mode 100644 index 000000000..48c1401fc --- /dev/null +++ b/share/smack/lib/smack-rust.c @@ -0,0 +1,49 @@ +#include +#include + +#define mk_signed_type(size) int##size##_t +#define mk_unsigned_type(size) uint##size##_t + +#define mk_signed_min(size) INT##size##_MIN +#define mk_signed_max(size) INT##size##_MAX +#define mk_unsigned_min(size) 0 +#define mk_unsigned_max(size) UINT##size##_MAX + +#define mk_smack_signed_nondet(size) __SMACK_nondet_i##size +#define mk_smack_unsigned_nondet(size) __SMACK_nondet_u##size +#define mk_smack_nondet_decl(size) \ + mk_signed_type(size) mk_smack_signed_nondet(size)(void); \ + mk_unsigned_type(size) mk_smack_unsigned_nondet(size)(void); + +#define mk_smack_nondet_def(size) \ + mk_signed_type(size) __VERIFIER_nondet_i##size(void) { \ + mk_signed_type(size) ret = mk_smack_signed_nondet(size)(); \ + if (ret < mk_signed_min(size) || ret > mk_signed_max(size)) \ + abort(); \ + return ret; \ + } \ + mk_unsigned_type(size) __VERIFIER_nondet_u##size(void) { \ + mk_unsigned_type(size) ret = mk_smack_unsigned_nondet(size)(); \ + if (ret < mk_unsigned_min(size) || ret > mk_unsigned_max(size)) \ + abort(); \ + return ret; \ + } + +#define mk_dummy_nondet_def(size) \ + mk_signed_type(size) __VERIFIER_nondet_i##size(void) { \ + return *((mk_signed_type(size) *)malloc(sizeof(mk_signed_type(size)))); \ + } \ + mk_unsigned_type(size) __VERIFIER_nondet_u##size(void) { \ + return *( \ + (mk_unsigned_type(size) *)malloc(sizeof(mk_unsigned_type(size)))); \ + } + +#if CARGO_BUILD +mk_dummy_nondet_def(8) mk_dummy_nondet_def(16) mk_dummy_nondet_def(32) + mk_dummy_nondet_def(64) void __VERIFIER_assert(int x) {} +void __VERIFIER_assume(int x) {} +#else +mk_smack_nondet_decl(8) mk_smack_nondet_decl(16) mk_smack_nondet_decl(32) + mk_smack_nondet_decl(64) mk_smack_nondet_def(8) mk_smack_nondet_def(16) + mk_smack_nondet_def(32) mk_smack_nondet_def(64) +#endif diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index c9f1cc9de..c0d7ae92d 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -41,50 +41,19 @@ void *__builtinx_va_arg(char *x) { long __builtinx_expect(long exp, long c) { return exp; } void __VERIFIER_assume(int x) { -#if !RUST_EXEC __SMACK_dummy(x); __SMACK_code("assume @ != $0;", x); -#endif } #ifndef CUSTOM_VERIFIER_ASSERT void __VERIFIER_assert(int x) { -#if !DISABLE_SMACK_ASSERTIONS && !RUST_EXEC +#if !DISABLE_SMACK_ASSERTIONS __SMACK_dummy(x); __SMACK_code("assert @ != $0;", x); #endif } #endif -#if RUST_EXEC -// Enable compatibility with Cargo compilation. -EMPTY_NONDET_DEFN(__SMACK_nondet, char); -EMPTY_NONDET_DEFN(__SMACK_nondet, signed, char); -EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, char); -EMPTY_NONDET_DEFN(__SMACK_nondet, short); -EMPTY_NONDET_DEFN(__SMACK_nondet, short, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, signed, short); -EMPTY_NONDET_DEFN(__SMACK_nondet, signed, short, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, short); -EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, short, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, signed, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned); -EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, long); -EMPTY_NONDET_DEFN(__SMACK_nondet, long, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, signed, long); -EMPTY_NONDET_DEFN(__SMACK_nondet, signed, long, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long); -EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, long, long); -EMPTY_NONDET_DEFN(__SMACK_nondet, long, long, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, signed, long, long); -EMPTY_NONDET_DEFN(__SMACK_nondet, signed, long, long, int); -EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long); -EMPTY_NONDET_DEFN(__SMACK_nondet, unsigned, long, long, int); -#endif // RUST_EXEC - int __SMACK_and32(int a, int b) { int c = 0; diff --git a/share/smack/lib/smack.rs b/share/smack/lib/smack.rs index 21ec33bc3..86aa447be 100644 --- a/share/smack/lib/smack.rs +++ b/share/smack/lib/smack.rs @@ -4,14 +4,14 @@ extern "C" { pub fn __VERIFIER_assert(x: i32); pub fn __VERIFIER_assume(x: i32); - pub fn __VERIFIER_nondet_signed_char() -> i8; - pub fn __VERIFIER_nondet_unsigned_char() -> u8; - pub fn __VERIFIER_nondet_signed_short() -> i16; - pub fn __VERIFIER_nondet_unsigned_short() -> u16; - pub fn __VERIFIER_nondet_signed_int() -> i32; - pub fn __VERIFIER_nondet_unsigned_int() -> u32; - pub fn __VERIFIER_nondet_signed_long_long() -> i64; - pub fn __VERIFIER_nondet_unsigned_long_long() -> u64; + pub fn __VERIFIER_nondet_i8() -> i8; + pub fn __VERIFIER_nondet_u8() -> u8; + pub fn __VERIFIER_nondet_i16() -> i16; + pub fn __VERIFIER_nondet_u16() -> u16; + pub fn __VERIFIER_nondet_i32() -> i32; + pub fn __VERIFIER_nondet_u32() -> u32; + pub fn __VERIFIER_nondet_i64() -> i64; + pub fn __VERIFIER_nondet_u64() -> u64; pub fn malloc(size: usize) -> *mut u8; pub fn __VERIFIER_memcpy(dest: *mut u8, src: *mut u8, count: usize) -> *mut u8; pub fn free(ptr: *mut u8); @@ -129,16 +129,16 @@ macro_rules! make_verifier_nondet { } /* Instantiate nondet for all integer types. */ -make_verifier_nondet!(i8, __VERIFIER_nondet_signed_char); -make_verifier_nondet!(u8, __VERIFIER_nondet_unsigned_char); -make_verifier_nondet!(i16, __VERIFIER_nondet_signed_short); -make_verifier_nondet!(u16, __VERIFIER_nondet_unsigned_short); -make_verifier_nondet!(i32, __VERIFIER_nondet_signed_int); -make_verifier_nondet!(u32, __VERIFIER_nondet_unsigned_int); -make_verifier_nondet!(i64, __VERIFIER_nondet_signed_long_long); -make_verifier_nondet!(u64, __VERIFIER_nondet_unsigned_long_long); -make_verifier_nondet!(isize, __VERIFIER_nondet_signed_long_long); -make_verifier_nondet!(usize, __VERIFIER_nondet_unsigned_long_long); +make_verifier_nondet!(i8, __VERIFIER_nondet_i8); +make_verifier_nondet!(u8, __VERIFIER_nondet_u8); +make_verifier_nondet!(i16, __VERIFIER_nondet_i16); +make_verifier_nondet!(u16, __VERIFIER_nondet_u16); +make_verifier_nondet!(i32, __VERIFIER_nondet_i32); +make_verifier_nondet!(u32, __VERIFIER_nondet_u32); +make_verifier_nondet!(i64, __VERIFIER_nondet_i64); +make_verifier_nondet!(u64, __VERIFIER_nondet_u64); +make_verifier_nondet!(isize, __VERIFIER_nondet_i64); +make_verifier_nondet!(usize, __VERIFIER_nondet_u64); #[cfg(not(verifier = "smack"))] #[cfg(feature = "std")] diff --git a/share/smack/lib/smack/build.rs b/share/smack/lib/smack/build.rs index 855d4c3f3..2f6c58cca 100644 --- a/share/smack/lib/smack/build.rs +++ b/share/smack/lib/smack/build.rs @@ -2,11 +2,11 @@ fn main() { cc::Build::new() - .file("src/smack.c") - .define("RUST_EXEC", None) + .file("src/smack-rust.c") + .define("CARGO_BUILD", None) .include("src") .compiler("clang") .compile("libsmack.a"); - println!("cargo:rerun-if-changed=src/smack.c"); + println!("cargo:rerun-if-changed=src/smack-rust.c"); } diff --git a/test/rust/cargo/cargo-test/Cargo.toml b/test/rust/cargo/cargo-test/Cargo.toml index 79063ada0..9e5aa6ccf 100644 --- a/test/rust/cargo/cargo-test/Cargo.toml +++ b/test/rust/cargo/cargo-test/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" [dependencies] num-traits = "0.2.12" -smack = { path = "/usr/local/share/smack/lib/smack" } \ No newline at end of file +smack = { path = "/usr/local/share/smack/lib" } From ffa82a232422ad930c9e4f18b3d3b6af2db8b316 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 16 Nov 2020 15:40:10 -0700 Subject: [PATCH 100/109] Updated sea-dsa --- sea-dsa | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-dsa b/sea-dsa index 77fa9ef09..4d460bb1f 160000 --- a/sea-dsa +++ b/sea-dsa @@ -1 +1 @@ -Subproject commit 77fa9ef0935aee4085a5ecdf52f67fcf2f87513b +Subproject commit 4d460bb1f013229b3a6c67770429a584d11959b8 From c627866d339807bf6a0851bb5974d88d59bc8834 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 16 Nov 2020 15:40:32 -0700 Subject: [PATCH 101/109] Install python3-toml --- bin/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build.sh b/bin/build.sh index b1d24f671..6995aabd5 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -63,7 +63,7 @@ CONFIGURE_INSTALL_PREFIX= CMAKE_INSTALL_PREFIX= # Partial list of dependencies; the rest are added depending on the platform -DEPENDENCIES="git cmake python3-yaml python3-psutil unzip wget ninja-build apt-transport-https dotnet-sdk-3.1 libboost-all-dev" +DEPENDENCIES="git cmake python3-yaml python3-psutil python3-toml unzip wget ninja-build apt-transport-https dotnet-sdk-3.1 libboost-all-dev" shopt -s extglob From d4066332384d27de6a72ea04577221bbedfb2561 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 16 Nov 2020 17:47:39 -0700 Subject: [PATCH 102/109] Revert "Updated sea-dsa" This reverts commit f224565e958bc84435e14078fe87e15fd1221890. --- sea-dsa | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-dsa b/sea-dsa index 4d460bb1f..77fa9ef09 160000 --- a/sea-dsa +++ b/sea-dsa @@ -1 +1 @@ -Subproject commit 4d460bb1f013229b3a6c67770429a584d11959b8 +Subproject commit 77fa9ef0935aee4085a5ecdf52f67fcf2f87513b From a48bfb75f542b4c17e344eca8ee15dc7e9f5ddeb Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 20 Nov 2020 23:50:58 -0700 Subject: [PATCH 103/109] Invocation of malloc with 0 size can return anything --- share/smack/lib/smack.c | 4 ---- test/c/memory-safety/malloc_nondet.c | 7 +++---- test/c/memory-safety/malloc_nondet_fail.c | 7 +++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index c9f1cc9de..a1d9e72a5 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -1092,8 +1092,6 @@ void __SMACK_decls(void) { " assume (forall q: ref :: {$base(q)} $sle.ref.bool(p, q) && " "$slt.ref.bool(q, $add.ref(p, n)) ==> $base(q) == p);\n" " $Alloc[p] := true;\n" - " } else {\n" - " p := $0.ref;\n" " }\n" "}\n"); @@ -1226,8 +1224,6 @@ void __SMACK_decls(void) { " assume $sge.ref.bool($sub.ref($CurrAddr, n), p);\n" " assume $sgt.ref.bool($CurrAddr, $0.ref) && $slt.ref.bool($CurrAddr, " "$MALLOC_TOP);\n" - " } else {\n" - " p := $0.ref;\n" " }\n" "}\n"); diff --git a/test/c/memory-safety/malloc_nondet.c b/test/c/memory-safety/malloc_nondet.c index fd29f42e6..9741ab826 100644 --- a/test/c/memory-safety/malloc_nondet.c +++ b/test/c/memory-safety/malloc_nondet.c @@ -5,10 +5,9 @@ int main(void) { int x = __VERIFIER_nondet_int(); + assume(x != 0); // malloc(0) can return anything char *p = (char *)malloc(x); - if (p != NULL) { - p[x - 1] = x; - free(p); - } + p[x - 1] = x; + free(p); return 0; } diff --git a/test/c/memory-safety/malloc_nondet_fail.c b/test/c/memory-safety/malloc_nondet_fail.c index 24fb37f76..52214619c 100644 --- a/test/c/memory-safety/malloc_nondet_fail.c +++ b/test/c/memory-safety/malloc_nondet_fail.c @@ -5,10 +5,9 @@ int main(void) { int x = __VERIFIER_nondet_int(); + assume(x != 0); // malloc(0) can return anything char *p = (char *)malloc(x); - if (p != NULL) { - p[x] = x; - free(p); - } + p[x] = x; + free(p); return 0; } From 129eda75b6d30ed7b9fcb248e771a13ab823302a Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Sat, 21 Nov 2020 02:09:44 -0700 Subject: [PATCH 104/109] Fixed assertion failures during witness generation --- share/smack/errtrace.py | 22 ++++++++++++++-------- share/smack/svcomp/utils.py | 2 +- share/smack/top.py | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/share/smack/errtrace.py b/share/smack/errtrace.py index f550d7480..72771ecda 100644 --- a/share/smack/errtrace.py +++ b/share/smack/errtrace.py @@ -130,23 +130,30 @@ def error_trace(verifier_output, args): return trace -def smackdOutput(corralOutput): +def smackdOutput(result, corralOutput): '''Convert error traces into JSON format''' + from .top import VResult + + if not (result is VResult.VERIFIED or result in VResult.ERROR): + return + FILENAME = r'[\w#$~%.\/-]+' traceP = re.compile( ('(' + FILENAME + r')\((\d+),(\d+)\): Trace: Thread=(\d+)\s+\((.*(;\n)?.*)\)')) - errorP = re.compile('(' + FILENAME + r')\((\d+),(\d+)\): (error .*)') + # test1.i(223,16): Trace: Thread=1 (ASSERTION FAILS assert false; + errorP = re.compile( + ('(' + + FILENAME + + r')\((\d+),(\d+)\): Trace: Thread=\d+\s+\(ASSERTION FAILS')) - passedMatch = re.search('Program has no bugs', corralOutput) - if passedMatch: + if result is VResult.VERIFIED: json_data = { 'verifier': 'corral', 'passed?': True } - else: traces = [] raw_data = re.findall(traceP, corralOutput) @@ -199,17 +206,16 @@ def smackdOutput(corralOutput): colno = int(errorMatch.group(3)) desc = str(errorMatch.group(4))""" errorMatch = errorP.search(corralOutput) - assert(errorMatch) + assert errorMatch, 'Failed to obtain assertion failure info!' filename = str(errorMatch.group(1)) lineno = int(errorMatch.group(2)) colno = int(errorMatch.group(3)) - desc = str(errorMatch.group(4)) failsAt = { 'file': filename, 'line': lineno, 'column': colno, - 'description': desc} + 'description': result.description()} json_data = { 'verifier': 'corral', diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 4cf857c8d..362c8f757 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -185,7 +185,7 @@ def write_error_file(args, status, verifier_output): if args.error_file: error = None if args.language == 'svcomp': - error = smackJsonToXmlGraph(smackdOutput(verifier_output), args, hasBug, status) + error = smackJsonToXmlGraph(smackdOutput(status, verifier_output), args, hasBug, status) elif hasBug: error = smack.top.error_trace(verifier_output, args) if error is not None: diff --git a/share/smack/top.py b/share/smack/top.py index 12013c4df..d7946da9b 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -913,7 +913,7 @@ def verify_bpl(args): result = verification_result(verifier_output) if args.smackd: - print(smackdOutput(verifier_output)) + print(smackdOutput(result, verifier_output)) else: if result in VResult.ERROR: error = error_trace(verifier_output, args) From efb074f74f3e9bb345965a39d1621ba4da04f661 Mon Sep 17 00:00:00 2001 From: Zvonimir Rakamaric Date: Mon, 23 Nov 2020 15:13:14 -0700 Subject: [PATCH 105/109] Improved the integer model of bit-wise and We are not modeling all the various key bit-widths. --- share/smack/lib/smack.c | 788 +++++++++++++++++++++++++++++++++++----- 1 file changed, 707 insertions(+), 81 deletions(-) diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index 1cd88181a..c4b79a802 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -59,363 +59,989 @@ int __SMACK_and32(int a, int b) { c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 2147483647) { c += 1; } } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } a = a % 2147483648; - b += b; + a += a; b = b % 2147483648; + b += b; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 2147483647) { c += 1; } } + a = a % 2147483648; a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } a = a % 2147483648; + a += a; + b = b % 2147483648; b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; b = b % 2147483648; + b += b; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 2147483647) { c += 1; } } + a = a % 2147483648; a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } a = a % 2147483648; + a += a; + b = b % 2147483648; b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; b = b % 2147483648; + b += b; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 2147483647) { c += 1; } } + a = a % 2147483648; a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } a = a % 2147483648; + a += a; + b = b % 2147483648; b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; b = b % 2147483648; + b += b; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 2147483647) { c += 1; } } + a = a % 2147483648; a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } a = a % 2147483648; + a += a; + b = b % 2147483648; b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; b = b % 2147483648; + b += b; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 2147483647) { c += 1; } } + a = a % 2147483648; a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } a = a % 2147483648; + a += a; + b = b % 2147483648; b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; b = b % 2147483648; + b += b; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 2147483647) { c += 1; } } + a = a % 2147483648; a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } a = a % 2147483648; + a += a; + b = b % 2147483648; b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; b = b % 2147483648; + b += b; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 2147483647) { c += 1; } } + a = a % 2147483648; a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } a = a % 2147483648; + a += a; + b = b % 2147483648; b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; b = b % 2147483648; + b += b; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 2147483647) { c += 1; } } + a = a % 2147483648; a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } a = a % 2147483648; + a += a; + b = b % 2147483648; b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; b = b % 2147483648; + b += b; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 2147483647) { c += 1; } } + a = a % 2147483648; a += a; + b = b % 2147483648; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } a = a % 2147483648; + a += a; + b = b % 2147483648; b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 2147483647) { + c += 1; + } + } + a = a % 2147483648; + a += a; b = b % 2147483648; + b += b; + + return c; +} + +long __SMACK_and64(long a, long b) { return (long)__SMACK_and32(a, b); } + +short __SMACK_and16(short a, short b) { + short c = 0; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 32767) { c += 1; } } + a = a % 32768; a += a; - a = a % 2147483648; + b = b % 32768; b += b; - b = b % 2147483648; + + return c; +} + +char __SMACK_and8(char a, char b) { + char c = 0; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 127) { c += 1; } } + a = a % 128; a += a; - a = a % 2147483648; + b = b % 128; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 127) { c += 1; } } + a = a % 128; a += a; - a = a % 2147483648; + b = b % 128; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 127) { c += 1; } } + a = a % 128; a += a; - a = a % 2147483648; + b = b % 128; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 127) { c += 1; } } + a = a % 128; a += a; - a = a % 2147483648; + b = b % 128; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 127) { c += 1; } } + a = a % 128; a += a; - a = a % 2147483648; + b = b % 128; b += b; - b = b % 2147483648; c += c; if (a < 0) { - if (b < 0) { + if (b < 0 || b > 127) { c += 1; } } + a = a % 128; a += a; - a = a % 2147483648; + b = b % 128; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 127) { + c += 1; + } + } + a = a % 128; + a += a; + b = b % 128; + b += b; + + c += c; + if (a < 0) { + if (b < 0 || b > 127) { + c += 1; + } + } + a = a % 128; + a += a; + b = b % 128; b += b; - b = b % 2147483648; return c; } -long __SMACK_and64(long a, long b) { return (long)__SMACK_and32(a, b); } -short __SMACK_and16(short a, short b) { return (short)__SMACK_and32(a, b); } -char __SMACK_and8(char a, char b) { return (char)__SMACK_and32(a, b); } - int __SMACK_or32(int a, int b) { int c = 0; From 725c335db6ac99970eb935af56f99b17cac51018 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Tue, 24 Nov 2020 22:45:22 -0700 Subject: [PATCH 106/109] Added internalize and dead global elimination passes --- tools/llvm2bpl/llvm2bpl.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/llvm2bpl/llvm2bpl.cpp b/tools/llvm2bpl/llvm2bpl.cpp index 85e1a5b37..a0ec23d28 100644 --- a/tools/llvm2bpl/llvm2bpl.cpp +++ b/tools/llvm2bpl/llvm2bpl.cpp @@ -33,6 +33,7 @@ #include "smack/InitializePasses.h" #include "smack/IntegerOverflowChecker.h" #include "smack/MemorySafetyChecker.h" +#include "smack/Naming.h" #include "smack/NormalizeLoops.h" #include "smack/RemoveDeadDefs.h" #include "smack/RewriteBitwiseOps.h" @@ -158,7 +159,21 @@ int main(int argc, char **argv) { // This runs before DSA because some Rust functions cause problems. pass_manager.add(new smack::RustFixes); - pass_manager.add(llvm::createDeadCodeEliminationPass()); + + if (!Modular) { + auto PreserveKeyGlobals = [=](const llvm::GlobalValue &GV) { + std::string name = GV.getName(); + return smack::SmackOptions::isEntryPoint(name) || + smack::Naming::isSmackName(name) || + name.find("__VERIFIER_assume") != std::string::npos; + }; + pass_manager.add(llvm::createInternalizePass(PreserveKeyGlobals)); + pass_manager.add(llvm::createGlobalDCEPass()); + pass_manager.add(llvm::createDeadCodeEliminationPass()); + pass_manager.add(llvm::createGlobalDCEPass()); + pass_manager.add(llvm::createDeadCodeEliminationPass()); + pass_manager.add(new smack::RemoveDeadDefs()); + } pass_manager.add(seadsa::createRemovePtrToIntPass()); pass_manager.add(llvm::createLowerSwitchPass()); From 2e2f4311554f39801e45895ade5e010c2eddd0f7 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 27 Nov 2020 12:59:37 -0700 Subject: [PATCH 107/109] Updated SMACK SVCOMP wrapper to set dotnet environment variables We are now bundling dotnet with SMACK. These updates make sure that the appropriate environment variables are set. --- bin/smack-svcomp-wrapper.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/smack-svcomp-wrapper.sh b/bin/smack-svcomp-wrapper.sh index dc709a856..5e3977d55 100755 --- a/bin/smack-svcomp-wrapper.sh +++ b/bin/smack-svcomp-wrapper.sh @@ -7,8 +7,10 @@ SMACK_BIN="${ROOT}/bin" BOOGIE_BIN="${ROOT}/smack-deps/boogie" CORRAL_BIN="${ROOT}/smack-deps/corral" Z3_BIN="${ROOT}/smack-deps/z3/bin" +DOTNET_BIN="${ROOT}/smack-deps/dotnet" -export PATH=${SMACK_BIN}:${BOOGIE_BIN}:${CORRAL_BIN}:${Z3_BIN}:$PATH +export DOTNET_ROOT=${DOTNET_BIN} +export PATH=${DOTNET_BIN}:${SMACK_BIN}:${BOOGIE_BIN}:${CORRAL_BIN}:${Z3_BIN}:$PATH smack -x=svcomp --verifier=svcomp -q $@ From bc39e8208813f713c59b842fdc4fa538bca92955 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Fri, 27 Nov 2020 16:14:57 -0700 Subject: [PATCH 108/109] Removed static loop bound for SVCOMP It seems that speeds up verification. --- share/smack/svcomp/utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index 362c8f757..71970efeb 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -109,13 +109,11 @@ def verify_bpl_svcomp(args): # Setting good loop unroll bound based on benchmark class loopUnrollBar = 13 - staticLoopBound = 64 time_limit = 880 command = list(corral_command) command += ["/timeLimit:%s" % time_limit] command += ["/v:1"] - command += ["/maxStaticLoopBound:%d" % staticLoopBound] command += ["/recursionBound:65536"] command += ["/irreducibleLoopUnroll:12"] command += ["/trackAllVars"] From b23527eca801d045545e62dcf3ed0565e22a0077 Mon Sep 17 00:00:00 2001 From: Zvonimir Date: Sat, 28 Nov 2020 00:21:31 -0700 Subject: [PATCH 109/109] Bumped version number to 2.6.1 --- Doxyfile | 2 +- share/smack/reach.py | 2 +- share/smack/top.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doxyfile b/Doxyfile index 9bc8b160c..eb6599c0c 100644 --- a/Doxyfile +++ b/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = smack -PROJECT_NUMBER = 2.6.0 +PROJECT_NUMBER = 2.6.1 PROJECT_BRIEF = "A bounded software verifier." PROJECT_LOGO = OUTPUT_DIRECTORY = docs diff --git a/share/smack/reach.py b/share/smack/reach.py index b06b7462a..a86dfb28c 100755 --- a/share/smack/reach.py +++ b/share/smack/reach.py @@ -11,7 +11,7 @@ from smackgen import * from smackverify import * -VERSION = '2.6.0' +VERSION = '2.6.1' def reachParser(): diff --git a/share/smack/top.py b/share/smack/top.py index d7946da9b..f1680db4a 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -13,7 +13,7 @@ from .frontend import link_bc_files, frontends, languages, extra_libs from .errtrace import error_trace, smackdOutput -VERSION = '2.6.0' +VERSION = '2.6.1' class VResult(Flag):