From 6385b6fbbf84887f75d919eed53dc32a410328b1 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Thu, 20 Apr 2023 11:43:42 +0000 Subject: [PATCH] Add size_of annotation to help CBMC's allocator CBMC's heap allocator will produce objects that aren't just a byte array when a prior call to `size_of` was involved in computing the number of bytes to be allocated via malloc/calloc/realloc. This, in turn, permits type-safe member accesses to heap-allocated objects. This should speed up copying as well as all other operations on the resulting object (which will then not have to go through byte extract/byte update operations). It also seems that there no longer is a "size_of" intrinsic. Fixes: #1286 Fixes: #1781 --- cprover_bindings/src/goto_program/expr.rs | 14 +++++- cprover_bindings/src/irep/to_irep.rs | 4 ++ .../codegen/intrinsic.rs | 8 ++-- .../codegen_cprover_gotoc/codegen/rvalue.rs | 3 +- .../Drop/drop_after_moving_across_channel.rs | 2 - .../fixme_drop_after_moving_across_channel.rs | 46 ------------------- 6 files changed, 23 insertions(+), 54 deletions(-) delete mode 100644 tests/kani/Drop/fixme_drop_after_moving_across_channel.rs diff --git a/cprover_bindings/src/goto_program/expr.rs b/cprover_bindings/src/goto_program/expr.rs index 7aae03f1538a..d9f23fff2916 100644 --- a/cprover_bindings/src/goto_program/expr.rs +++ b/cprover_bindings/src/goto_program/expr.rs @@ -41,6 +41,7 @@ pub struct Expr { value: Box, typ: Type, location: Location, + size_of_annotation: Option, } /// The different kinds of values an expression can have. @@ -293,6 +294,10 @@ impl Expr { &self.value } + pub fn size_of_annotation(&self) -> &Option { + &self.size_of_annotation + } + /// If the expression is an Int constant type, return its value pub fn int_constant_value(&self) -> Option { match &*self.value { @@ -404,12 +409,19 @@ impl Expr { } } +impl Expr { + pub fn with_size_of_annotation(mut self, ty: Type) -> Self { + self.size_of_annotation = Some(ty); + self + } +} + /// Private constructor. Making this a macro allows multiple reference to self in the same call. macro_rules! expr { ( $value:expr, $typ:expr) => {{ let typ = $typ; let value = Box::new($value); - Expr { value, typ, location: Location::none() } + Expr { value, typ, location: Location::none(), size_of_annotation: None } }}; } diff --git a/cprover_bindings/src/irep/to_irep.rs b/cprover_bindings/src/irep/to_irep.rs index 3ba02e3bd97f..4d47aee630b0 100644 --- a/cprover_bindings/src/irep/to_irep.rs +++ b/cprover_bindings/src/irep/to_irep.rs @@ -162,6 +162,10 @@ impl ToIrep for Expr { } else { self.value().to_irep(mm).with_location(self.location(), mm).with_type(self.typ(), mm) } + .with_named_sub_option( + IrepId::CCSizeofType, + self.size_of_annotation().clone().map(|ty| ty.to_irep(mm)), + ) } } diff --git a/kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs b/kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs index d657de37c601..3cbe4f0be88f 100644 --- a/kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs +++ b/kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs @@ -288,7 +288,7 @@ impl<'tcx> GotocCtx<'tcx> { }}; } - // Intrinsics which encode a value known during compilation (e.g., `size_of`) + // Intrinsics which encode a value known during compilation macro_rules! codegen_intrinsic_const { () => {{ let value = self @@ -611,7 +611,6 @@ impl<'tcx> GotocCtx<'tcx> { loc, ), "simd_xor" => codegen_intrinsic_binop!(bitxor), - "size_of" => codegen_intrinsic_const!(), "size_of_val" => codegen_size_align!(size), "sqrtf32" => unstable_codegen!(codegen_simple_intrinsic!(Sqrtf)), "sqrtf64" => unstable_codegen!(codegen_simple_intrinsic!(Sqrt)), @@ -1267,11 +1266,12 @@ impl<'tcx> GotocCtx<'tcx> { /// This function computes the size and alignment of a dynamically-sized type. /// The implementations follows closely the SSA implementation found in /// `rustc_codegen_ssa::glue::size_and_align_of_dst`. - fn size_and_align_of_dst(&self, t: Ty<'tcx>, arg: Expr) -> SizeAlign { + fn size_and_align_of_dst(&mut self, t: Ty<'tcx>, arg: Expr) -> SizeAlign { let layout = self.layout_of(t); let usizet = Type::size_t(); if !layout.is_unsized() { - let size = Expr::int_constant(layout.size.bytes_usize(), Type::size_t()); + let size = Expr::int_constant(layout.size.bytes_usize(), Type::size_t()) + .with_size_of_annotation(self.codegen_ty(t)); let align = Expr::int_constant(layout.align.abi.bytes(), usizet); return SizeAlign { size, align }; } diff --git a/kani-compiler/src/codegen_cprover_gotoc/codegen/rvalue.rs b/kani-compiler/src/codegen_cprover_gotoc/codegen/rvalue.rs index 29d636cc4150..a979160f1bf1 100644 --- a/kani-compiler/src/codegen_cprover_gotoc/codegen/rvalue.rs +++ b/kani-compiler/src/codegen_cprover_gotoc/codegen/rvalue.rs @@ -509,7 +509,8 @@ impl<'tcx> GotocCtx<'tcx> { let t = self.monomorphize(*t); let layout = self.layout_of(t); match k { - NullOp::SizeOf => Expr::int_constant(layout.size.bytes_usize(), Type::size_t()), + NullOp::SizeOf => Expr::int_constant(layout.size.bytes_usize(), Type::size_t()) + .with_size_of_annotation(self.codegen_ty(t)), NullOp::AlignOf => Expr::int_constant(layout.align.abi.bytes(), Type::size_t()), } } diff --git a/tests/kani/Drop/drop_after_moving_across_channel.rs b/tests/kani/Drop/drop_after_moving_across_channel.rs index f06f7b3fa1e7..1c59e2e404e9 100644 --- a/tests/kani/Drop/drop_after_moving_across_channel.rs +++ b/tests/kani/Drop/drop_after_moving_across_channel.rs @@ -3,8 +3,6 @@ //! This test checks whether dropping objects passed through //! std::sync::mpsc::channel is handled. -//! This test only passes on MacOS today, so we duplicate the test for now. -#![cfg(target_os = "macos")] use std::sync::mpsc::*; diff --git a/tests/kani/Drop/fixme_drop_after_moving_across_channel.rs b/tests/kani/Drop/fixme_drop_after_moving_across_channel.rs deleted file mode 100644 index a66d7df7cf36..000000000000 --- a/tests/kani/Drop/fixme_drop_after_moving_across_channel.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright Kani Contributors -// SPDX-License-Identifier: Apache-2.0 OR MIT - -//! This test checks whether dropping objects passed through -//! std::sync::mpsc::channel is handled. -// -// This test case fails to resolve in a reasonable amount of -// time. Settign kani::unwind(1) is insufficient for verification, but -// kani::unwind(2) takes longer than 10m on a M1 Mac. For details, -// please see: https://github.com/model-checking/kani/issues/1286 - -#[cfg(target_os = "linux")] -mod fixme_harness { - use std::sync::mpsc::*; - - static mut CELL: i32 = 0; - - struct DropSetCELLToOne {} - - impl Drop for DropSetCELLToOne { - fn drop(&mut self) { - unsafe { - CELL = 1; - } - } - } - - #[kani::unwind(1)] - #[kani::proof] - fn main() { - { - let (send, recv) = channel::(); - send.send(DropSetCELLToOne {}).unwrap(); - let _to_drop: DropSetCELLToOne = recv.recv().unwrap(); - } - assert_eq!(unsafe { CELL }, 1, "Drop should be called"); - } -} - -#[cfg(target_os = "macos")] -mod forced_failure { - #[kani::proof] - fn just_panic() { - panic!("This test only fails on linux"); - } -}