Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Towards Proving Memory Initialization #3264

Merged
merged 99 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
52c01aa
Towards implementing uninitialized memory detection in raw pointers
artemagvanian Jun 11, 2024
2b73af7
Implement uninitialized memory detection in raw pointers for certain …
artemagvanian Jun 12, 2024
f3edc52
Implement wide pointer decomposition as part of kani library
artemagvanian Jun 13, 2024
57c31d4
Ensure checks are executed before instructions and statements -- after
artemagvanian Jun 13, 2024
1006fbe
Move tests under tests/kani
artemagvanian Jun 14, 2024
fc224de
Implement drop blessing
artemagvanian Jun 14, 2024
c755ac9
Fix check insertion order
artemagvanian Jun 14, 2024
9b2be02
Autoinitialize extern in alloc::alloc
artemagvanian Jun 14, 2024
e901ebb
Implement support for vtable wide pointers
artemagvanian Jun 14, 2024
4e0c348
Clean up tests, preserve types in shadow memory calls
artemagvanian Jun 17, 2024
1d6e167
Skip analyzing pointers to trait objects for now
artemagvanian Jun 17, 2024
7e26dac
Slight cleanup
artemagvanian Jun 17, 2024
da8c891
Merge branch 'main' into main
artemagvanian Jun 17, 2024
c8a8d1f
Update code to work with nightly-2024-06-17
artemagvanian Jun 17, 2024
087090a
Add missing copyright statements
artemagvanian Jun 17, 2024
73a7ccb
Make clippy happy
artemagvanian Jun 17, 2024
1e55cb7
Make clippy even happier
artemagvanian Jun 17, 2024
97ce8a2
Implement an option to enable initialization checks as a part of func…
artemagvanian Jun 18, 2024
459acba
Separate `can_dereference` from `is_initialized` for now
artemagvanian Jun 18, 2024
d3ab562
Filter out all instances without body to fix MIR dumping
artemagvanian Jun 18, 2024
73ae723
Handle intrinsics exhaustively
artemagvanian Jun 18, 2024
54a3970
Fix code formatting
artemagvanian Jun 18, 2024
8aa56e3
Disable initializations checks in `std-checks` to make CI pass
artemagvanian Jun 19, 2024
d833c2b
Merge branch 'main' into main
artemagvanian Jun 19, 2024
aefec83
Automatically add global shadow memory to `modifies` contract clause
artemagvanian Jun 19, 2024
7a72bbd
Only inject shadow memory symbol if defined
artemagvanian Jun 19, 2024
09f8ecc
Make clippy happy
artemagvanian Jun 19, 2024
ca4da40
Remove stray unwrap
artemagvanian Jun 19, 2024
3bdc949
Add memory initialization checks to `std-verify`
artemagvanian Jun 19, 2024
55b62c4
Fix `expected` files
artemagvanian Jun 19, 2024
e983934
Adjust container size for the harness
artemagvanian Jun 19, 2024
0c8ec39
Skip initialization checks based on the attribute
artemagvanian Jun 20, 2024
2986704
Add comment explaining `skip_first`
artemagvanian Jun 20, 2024
4a43c95
Cache the result of `find_fn_def`
artemagvanian Jun 20, 2024
405e34a
Refactor code re: comments
artemagvanian Jun 20, 2024
ba2d5df
More refactoring for cleaner type layout
artemagvanian Jun 20, 2024
a729cd2
Undo temporary fix to `--emit mir`
artemagvanian Jun 20, 2024
c61b16d
Move `skip_first` from MutableBody to transformation pass
artemagvanian Jun 20, 2024
4feda97
Add some docs for `is_initialized_body`
artemagvanian Jun 20, 2024
d9eacd7
Remove `transmute` inside `shadow.rs`, document type layout, carve ou…
artemagvanian Jun 20, 2024
7174eba
Incorporate `is_initialized` into `can_dereference` and `can_read_una…
artemagvanian Jun 20, 2024
d4ced45
Add more comments to `UninitPass`
artemagvanian Jun 21, 2024
0ec8c3b
Merge branch 'main' into main
artemagvanian Jun 21, 2024
2640b3f
Fix bug when inserting a terminator after a terminator
artemagvanian Jun 21, 2024
98e8a37
Put memory initialization checking into a separate module
artemagvanian Jun 24, 2024
cc32650
Add initialization checks into `kani::mem`
artemagvanian Jun 24, 2024
3dbf70d
Perform FnDef caching inside instrumentation passes
artemagvanian Jun 24, 2024
226c502
Only expose byte mask for type layout
artemagvanian Jun 24, 2024
839a79c
Update a comment
artemagvanian Jun 24, 2024
d6423ce
Further changes to `ty_layout`
artemagvanian Jun 24, 2024
a74bad0
Further changed to`kani_intrinsics`
artemagvanian Jun 24, 2024
54f6284
Extract function resolution associated with `get_kani_sm_function` in…
artemagvanian Jun 24, 2024
1760369
Support determining type layout of enums with variants of the exact s…
artemagvanian Jun 24, 2024
4894296
`assert(false)` on using pointers to trait objects
artemagvanian Jun 24, 2024
db309e0
Make clippy happy
artemagvanian Jun 24, 2024
dc99603
Merge branch 'main' into main
artemagvanian Jun 24, 2024
1718666
Remove unnecessary call to `ty_size`
artemagvanian Jun 24, 2024
dd71adf
Move tests around, temporarily disable `std-checks`
artemagvanian Jun 24, 2024
224239f
Split `split_bb` into two functions
artemagvanian Jun 25, 2024
496bb8b
Merge branch 'main' into main
artemagvanian Jun 25, 2024
9706df2
Add missing `is_initialized` definition into `kani_core`
artemagvanian Jun 25, 2024
43f88c6
Temporarily decouple `is_initialized` and `can_dereference` so that C…
artemagvanian Jun 25, 2024
4d7a97f
Add missing flag
artemagvanian Jun 25, 2024
1a80d98
Formatting change
artemagvanian Jun 25, 2024
ab6fbc9
Disable memory initialization checks for `std-core`
artemagvanian Jun 25, 2024
438a3b4
Fix determining type layout for enums
artemagvanian Jun 25, 2024
e7f3972
Make `is_initialized` a noop if `-Z uninit-checks` flag is not set
artemagvanian Jun 25, 2024
58e62eb
Merge branch 'main' into main
artemagvanian Jun 25, 2024
910f555
Clean up test files
artemagvanian Jun 26, 2024
5966c81
Fix comments inside some tests
artemagvanian Jun 26, 2024
37c03c4
Fix function documentation
artemagvanian Jun 26, 2024
6a7ea31
Small formatting change
artemagvanian Jun 26, 2024
6146a4b
Changes to `slice.rs`
artemagvanian Jun 27, 2024
ce454a3
Merge `mem_swap` and `mem_replace` into `mem`
artemagvanian Jun 27, 2024
3dab8d3
Rename `try_mark_new_bb_as_skipped`
artemagvanian Jun 27, 2024
2e34fa5
Mark changing the initialization state of a trait object as unreachable
artemagvanian Jun 27, 2024
96238df
Add a better comment for `mk_layout_operand`
artemagvanian Jun 27, 2024
01fb654
Add a better doc comment to `Layout`
artemagvanian Jun 27, 2024
e42bdfd
Rename `SourceOp` to `MemoryInitOp`, add comments
artemagvanian Jun 27, 2024
2fe3c7c
Remove unnecessary fields in `MemoryInitOp::Get` and `MemoryInitOp::U…
artemagvanian Jun 27, 2024
d924a9b
Pre-filter intrinsics before instrumenting them
artemagvanian Jun 27, 2024
0136480
Add comment about instrumentation pass order
artemagvanian Jun 27, 2024
1996b05
Merge branch 'main' into main
artemagvanian Jun 27, 2024
9edcd6a
Assert that enum tag has the offset of zero
artemagvanian Jun 27, 2024
c75b616
Inline `scalar_ty_size`
artemagvanian Jun 27, 2024
f4ac75c
Merge branch 'main' into main
artemagvanian Jun 27, 2024
683d365
Apply changes from comments to `perf/uninit`
artemagvanian Jun 28, 2024
28b3a03
Merge branch 'main' into main
artemagvanian Jun 28, 2024
90af616
Add extra docs to `UninitVisitor`
artemagvanian Jun 28, 2024
4b8dcd5
Move some functions in `uninit_visitor.rs` around
artemagvanian Jun 28, 2024
1ab140b
Reorganize handling of intrinsics
artemagvanian Jun 28, 2024
f266ea9
Rename `MemoryInitOp::Get` to `MemoryInitOp::Check`
artemagvanian Jun 28, 2024
a1dccb2
Throw an error only if the unsize cast happens to a pointer to trait …
artemagvanian Jun 28, 2024
bbfd443
Add logic to track additional pointer dereferences in `StatementKind:…
artemagvanian Jun 28, 2024
b882bce
Merge branch 'main' into main
artemagvanian Jul 1, 2024
bda552e
Merge branch 'main' into main
artemagvanian Jul 1, 2024
ca62743
Merge branch 'main' into main
artemagvanian Jul 2, 2024
c91496f
Update kani-compiler/src/kani_middle/transform/check_uninit/uninit_vi…
artemagvanian Jul 2, 2024
839df71
Update incorrect comment in `uninit_visitor.rs`
artemagvanian Jul 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions kani-compiler/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,6 @@ pub enum ExtraChecks {
/// Check pointer validity when casting pointers to references.
/// See https://github.com/model-checking/kani/issues/2975.
PtrToRefCast,
/// Check for using uninitialized memory.
Uninit,
}
2 changes: 1 addition & 1 deletion kani-compiler/src/codegen_cprover_gotoc/overrides/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ impl GotocHook for PointerObject {
) -> Stmt {
assert_eq!(fargs.len(), 1);
let ptr = fargs.pop().unwrap().cast_to(Type::void_pointer());
let target = target.unwrap();
let target: usize = target.unwrap();
let loc = gcx.codegen_caller_span_stable(span);
let ret_place =
unwrap_or_return_codegen_unimplemented_stmt!(gcx, gcx.codegen_place_stable(assign_to));
Expand Down
215 changes: 182 additions & 33 deletions kani-compiler/src/kani_middle/transform/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use stable_mir::mir::{
VarDebugInfo,
};
use stable_mir::ty::{Const, GenericArgs, Span, Ty, UintTy};
use std::collections::HashSet;
use std::fmt::Debug;
use std::mem;

Expand Down Expand Up @@ -39,6 +40,15 @@ pub struct MutableBody {

/// The span that covers the entire function body.
span: Span,

/// Set of basic block indices for which analyzing first statement should be skipped.
artemagvanian marked this conversation as resolved.
Show resolved Hide resolved
skip_first: HashSet<usize>,
}

#[derive(Debug, Clone, Copy)]
pub enum InsertPosition {
Before,
After,
}

impl MutableBody {
Expand All @@ -60,9 +70,14 @@ impl MutableBody {
blocks: body.blocks,
var_debug_info: body.var_debug_info,
span: body.span,
skip_first: HashSet::new(),
}
}

pub fn skip_first(&self, bb_idx: usize) -> bool {
self.skip_first.contains(&bb_idx)
}

/// Create the new body consuming this mutable body.
pub fn into(self) -> Body {
Body::new(
Expand Down Expand Up @@ -99,12 +114,28 @@ impl MutableBody {
from: Operand,
pointee_ty: Ty,
mutability: Mutability,
before: &mut SourceInstruction,
where_to: &mut SourceInstruction,
insert_position: InsertPosition,
) -> Local {
assert!(from.ty(self.locals()).unwrap().kind().is_raw_ptr());
let target_ty = Ty::new_ptr(pointee_ty, mutability);
let rvalue = Rvalue::Cast(CastKind::PtrToPtr, from, target_ty);
self.new_assignment(rvalue, before)
self.new_assignment(rvalue, where_to, insert_position)
}

/// Transmute to a raw pointer of `*mut type` and return a new local where that value is stored.
pub fn new_cast_transmute(
&mut self,
from: Operand,
pointee_ty: Ty,
mutability: Mutability,
where_to: &mut SourceInstruction,
insert_position: InsertPosition,
) -> Local {
assert!(from.ty(self.locals()).unwrap().kind().is_raw_ptr());
let target_ty = Ty::new_ptr(pointee_ty, mutability);
let rvalue = Rvalue::Cast(CastKind::Transmute, from, target_ty);
self.new_assignment(rvalue, where_to, insert_position)
}

/// Add a new assignment for the given binary operation.
Expand All @@ -115,21 +146,27 @@ impl MutableBody {
bin_op: BinOp,
lhs: Operand,
rhs: Operand,
before: &mut SourceInstruction,
where_to: &mut SourceInstruction,
insert_position: InsertPosition,
) -> Local {
let rvalue = Rvalue::BinaryOp(bin_op, lhs, rhs);
self.new_assignment(rvalue, before)
self.new_assignment(rvalue, where_to, insert_position)
}

/// Add a new assignment.
///
/// Return local where the result is saved.
pub fn new_assignment(&mut self, rvalue: Rvalue, before: &mut SourceInstruction) -> Local {
let span = before.span(&self.blocks);
pub fn new_assignment(
&mut self,
rvalue: Rvalue,
where_to: &mut SourceInstruction,
insert_position: InsertPosition,
) -> Local {
let span = where_to.span(&self.blocks);
let ret_ty = rvalue.ty(&self.locals).unwrap();
let result = self.new_local(ret_ty, span, Mutability::Not);
let stmt = Statement { kind: StatementKind::Assign(Place::from(result), rvalue), span };
self.insert_stmt(stmt, before);
self.insert_stmt(stmt, where_to, insert_position);
result
}

Expand All @@ -143,6 +180,7 @@ impl MutableBody {
tcx: TyCtxt,
check_type: &CheckType,
source: &mut SourceInstruction,
insert_position: InsertPosition,
value: Local,
msg: &str,
) {
Expand Down Expand Up @@ -172,7 +210,7 @@ impl MutableBody {
unwind: UnwindAction::Terminate,
};
let terminator = Terminator { kind, span };
self.split_bb(source, terminator);
self.split_bb(source, insert_position, terminator);
}
CheckType::Panic | CheckType::NoCore => {
tcx.sess
Expand All @@ -186,42 +224,153 @@ impl MutableBody {
}
}

/// Add a new call to the basic block indicated by the given index.
///
/// The new call will have the same span as the source instruction, and the basic block
/// will be split. The source instruction will be adjusted to point to the first instruction in
/// the new basic block.
pub fn add_call(
&mut self,
callee: &Instance,
source: &mut SourceInstruction,
insert_position: InsertPosition,
args: Vec<Operand>,
destination: Place,
) {
let new_bb = self.blocks.len();
let span = source.span(&self.blocks);
let callee_op =
Operand::Copy(Place::from(self.new_local(callee.ty(), span, Mutability::Not)));
let kind = TerminatorKind::Call {
func: callee_op,
args,
destination,
target: Some(new_bb),
unwind: UnwindAction::Terminate,
};
let terminator = Terminator { kind, span };
self.split_bb(source, insert_position, terminator);
}

/// Split a basic block right before the source location and use the new terminator
/// in the basic block that was split.
///
/// The source is updated to point to the same instruction which is now in the new basic block.
pub fn split_bb(&mut self, source: &mut SourceInstruction, new_term: Terminator) {
pub fn split_bb(
&mut self,
source: &mut SourceInstruction,
insert_position: InsertPosition,
new_term: Terminator,
) {
let new_bb_idx = self.blocks.len();
let (idx, bb) = match source {
artemagvanian marked this conversation as resolved.
Show resolved Hide resolved
SourceInstruction::Statement { idx, bb } => {
let (orig_idx, orig_bb) = (*idx, *bb);
*idx = 0;
*bb = new_bb_idx;
(orig_idx, orig_bb)
match insert_position {
InsertPosition::Before => {
let (idx, bb) = match source {
SourceInstruction::Statement { idx, bb } => {
let (orig_idx, orig_bb) = (*idx, *bb);
*idx = 0;
*bb = new_bb_idx;
(orig_idx, orig_bb)
}
SourceInstruction::Terminator { bb } => {
let (orig_idx, orig_bb) = (self.blocks[*bb].statements.len(), *bb);
*bb = new_bb_idx;
(orig_idx, orig_bb)
}
};
let old_term = mem::replace(&mut self.blocks[bb].terminator, new_term);
let bb_stmts = &mut self.blocks[bb].statements;
let remaining = bb_stmts.split_off(idx);
let new_bb = BasicBlock { statements: remaining, terminator: old_term };
self.blocks.push(new_bb);
self.skip_first.insert(new_bb_idx);
}
SourceInstruction::Terminator { bb } => {
let orig_bb = *bb;
*bb = new_bb_idx;
(self.blocks[orig_bb].statements.len(), orig_bb)
InsertPosition::After => {
let span = source.span(&self.blocks);
match source {
SourceInstruction::Statement { idx, bb } => {
let (orig_idx, orig_bb) = (*idx, *bb);
*idx = 0;
*bb = new_bb_idx;
let old_term = mem::replace(&mut self.blocks[orig_bb].terminator, new_term);
let bb_stmts = &mut self.blocks[orig_bb].statements;
let remaining = bb_stmts.split_off(orig_idx + 1);
let new_bb = BasicBlock { statements: remaining, terminator: old_term };
self.blocks.push(new_bb);
}
SourceInstruction::Terminator { bb } => {
let current_terminator = &mut self.blocks.get_mut(*bb).unwrap().terminator;
// Kani can only instrument function calls in this way.
match &mut current_terminator.kind {
TerminatorKind::Call { target: Some(target_bb), .. } => {
*bb = new_bb_idx;
let new_bb = BasicBlock {
statements: vec![],
terminator: Terminator {
kind: TerminatorKind::Goto { target: *target_bb },
span,
},
};
*target_bb = new_bb_idx;
self.blocks.push(new_bb);
}
_ => unimplemented!("Kani can only split blocks after calls."),
};
}
};
}
};
let old_term = mem::replace(&mut self.blocks[bb].terminator, new_term);
let bb_stmts = &mut self.blocks[bb].statements;
let remaining = bb_stmts.split_off(idx);
let new_bb = BasicBlock { statements: remaining, terminator: old_term };
self.blocks.push(new_bb);
}
}

/// Insert statement before the source instruction and update the source as needed.
pub fn insert_stmt(&mut self, new_stmt: Statement, before: &mut SourceInstruction) {
match before {
SourceInstruction::Statement { idx, bb } => {
self.blocks[*bb].statements.insert(*idx, new_stmt);
*idx += 1;
pub fn insert_stmt(
&mut self,
new_stmt: Statement,
where_to: &mut SourceInstruction,
insert_position: InsertPosition,
) {
match insert_position {
InsertPosition::Before => {
match where_to {
SourceInstruction::Statement { idx, bb } => {
self.blocks[*bb].statements.insert(*idx, new_stmt);
*idx += 1;
}
SourceInstruction::Terminator { bb } => {
// Append statements at the end of the basic block.
self.blocks[*bb].statements.push(new_stmt);
}
}
}
SourceInstruction::Terminator { bb } => {
// Append statements at the end of the basic block.
self.blocks[*bb].statements.push(new_stmt);
InsertPosition::After => {
let new_bb_idx = self.blocks.len();
let span = where_to.span(&self.blocks);
match where_to {
SourceInstruction::Statement { idx, bb } => {
self.blocks[*bb].statements.insert(*idx + 1, new_stmt);
*idx += 1;
}
SourceInstruction::Terminator { bb } => {
// Create a new basic block, as we need to append a statement after the terminator.
let current_terminator = &mut self.blocks.get_mut(*bb).unwrap().terminator;
// Kani can only instrument function calls in this way.
match &mut current_terminator.kind {
TerminatorKind::Call { target: Some(target_bb), .. } => {
*where_to = SourceInstruction::Statement { idx: 0, bb: new_bb_idx };
let new_bb = BasicBlock {
statements: vec![new_stmt],
terminator: Terminator {
kind: TerminatorKind::Goto { target: *target_bb },
span,
},
};
*target_bb = new_bb_idx;
self.blocks.push(new_bb);
}
_ => unimplemented!("Kani can only insert statements after calls."),
};
}
}
}
}
}
Expand Down
Loading
Loading