Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,5 @@ src/test/rustdoc-gui/src/**.lock
/.ninja_deps
/.ninja_log
/src/test/dashboard
*Cargo.lock
src/test/rmc-dependency-test/diamond-dependency/build
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ exclude = [
"src/tools/x",
# stdarch has its own Cargo workspace
"library/stdarch",
# dependency tests have their own workspace
"src/test/rmc-dependency-test/dependency3"
]

[profile.release.package.compiler_builtins]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::gotoc::cbmc::goto_program::{Expr, Location, Stmt, Symbol, Type};
use crate::gotoc::mir_to_goto::utils::slice_fat_ptr;
use crate::gotoc::mir_to_goto::GotocCtx;
use rustc_ast::ast::Mutability;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::mir::interpret::{
read_target_uint, AllocId, Allocation, ConstValue, GlobalAlloc, Scalar,
};
Expand Down Expand Up @@ -353,9 +352,10 @@ impl<'tcx> GotocCtx<'tcx> {
sym.clone().to_expr().address_of()
}
GlobalAlloc::Memory(alloc) => {
// crate_name added so that allocations in different crates don't clash
let crate_name = self.tcx.crate_name(LOCAL_CRATE);
let name = format!("{}::{:?}", crate_name, alloc_id);
// Full (mangled) crate name added so that allocations from different
// crates do not conflict. The name alone is insufficient becase Rust
// allows different versions of the same crate to be used.
let name = format!("{}::{:?}", self.full_crate_name(), alloc_id);
self.codegen_allocation(alloc, |_| name.clone(), Some(name.clone()))
}
};
Expand Down
24 changes: 23 additions & 1 deletion compiler/rustc_codegen_llvm/src/gotoc/mir_to_goto/codegen/typ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,21 @@ impl<'tcx> GotocCtx<'tcx> {
// code. See the implementation of pretty_print_region on line 1720 in
// compiler/rustc_middle/src/ty/print/pretty.rs.
let name = name.replace(" + \'static", "").replace("\'static ", "");
name

// Crate resolution: mangled names need to be distinct across different versions
// of the same crate that could be pulled in by dependencies. However, RMC's
// treatment of FFI C calls asssumes that we generate the same name for structs
// as the C name, so don't mangle in that case.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a hack. We should note it as such, and have a tracking issue to do the right thing here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed and adding

// TODO: this is likely insufficient if a dependent crate has two versions of
// linked C libraries
// https://github.com/model-checking/rmc/issues/450
if is_repr_c_adt(t) {
return name;
}

// Add unique type id
let id_u64 = self.tcx.type_id_hash(t);
format!("{}::{}", name, id_u64)
}

#[allow(dead_code)]
Expand Down Expand Up @@ -1201,6 +1215,14 @@ pub fn pointee_type(pointer_type: Ty<'tcx>) -> Option<Ty<'tcx>> {
}
}

/// Is the MIR type using a C representation (marked with #[repr(C)] at the source level)?
pub fn is_repr_c_adt(mir_type: Ty<'tcx>) -> bool {
match mir_type.kind() {
ty::Adt(def, _) => def.repr.c(),
_ => false,
}
}

impl<'tcx> GotocCtx<'tcx> {
/// A pointer to the mir type should be a thin pointer.
pub fn use_thin_pointer(&self, mir_type: Ty<'tcx>) -> bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl CodegenBackend for GotocCodegenBackend {
MonoItem::GlobalAsm(_) => {
warn!(
"Crate {} contains global ASM, which is not handled by RMC",
c.crate_name()
c.short_crate_name()
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ use crate::gotoc::cbmc::goto_program::{
use crate::gotoc::cbmc::utils::aggr_name;
use crate::gotoc::cbmc::{MachineModel, RoundingMode};
use crate::gotoc::mir_to_goto::overrides::{type_and_fn_hooks, GotocHooks, GotocTypeHooks};
use crate::gotoc::mir_to_goto::utils::full_crate_name;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::rustc_erase_owner;
use rustc_data_structures::stable_map::FxHashMap;
use rustc_data_structures::sync::MetadataRef;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::middle::cstore::MetadataLoader;
use rustc_middle::mir::interpret::Allocation;
use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, TyAndLayout};
Expand All @@ -43,6 +43,8 @@ pub struct GotocCtx<'tcx> {
pub symbol_table: SymbolTable,
pub hooks: GotocHooks<'tcx>,
pub type_hooks: GotocTypeHooks<'tcx>,
/// the full crate name, including versioning info
pub full_crate_name: String,
/// a global counter for generating unique names for global variables
pub global_var_count: u64,
/// map a global allocation to a name in the symbol table
Expand All @@ -61,6 +63,7 @@ impl<'tcx> GotocCtx<'tcx> {
symbol_table,
hooks: fhks,
type_hooks: thks,
full_crate_name: full_crate_name(tcx),
global_var_count: 0,
alloc_map: FxHashMap::default(),
current_fn: None,
Expand All @@ -70,10 +73,6 @@ impl<'tcx> GotocCtx<'tcx> {

/// Getters
impl<'tcx> GotocCtx<'tcx> {
pub fn crate_name(&self) -> String {
self.tcx.crate_name(LOCAL_CRATE).to_string()
}

pub fn current_fn(&self) -> &CurrentFnCtx<'tcx> {
self.current_fn.as_ref().unwrap()
}
Expand Down Expand Up @@ -225,7 +224,7 @@ impl<'tcx> GotocCtx<'tcx> {
pub fn next_global_name(&mut self) -> String {
let c = self.global_var_count;
self.global_var_count += 1;
format!("{}::global::{}::", self.tcx.crate_name(LOCAL_CRATE), c)
format!("{}::global::{}::", self.full_crate_name(), c)
}
}

Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_codegen_llvm/src/gotoc/mir_to_goto/utils/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@

use crate::gotoc::mir_to_goto::GotocCtx;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::definitions::DefPathDataName;
use rustc_middle::mir::mono::CodegenUnitNameBuilder;
use rustc_middle::mir::Local;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Instance, TyCtxt};
use tracing::debug;

impl<'tcx> GotocCtx<'tcx> {
/// The short crate name without versioning information.
pub fn short_crate_name(&self) -> String {
self.tcx.crate_name(LOCAL_CRATE).to_string()
}

/// The full crate name including versioning info
pub fn full_crate_name(&self) -> &str {
&self.full_crate_name
}

pub fn codegen_var_base_name(&self, l: &Local) -> String {
match self.find_debug_info(l) {
None => format!("var_{}", l.index()),
Expand Down Expand Up @@ -98,6 +110,21 @@ impl<'tcx> GotocCtx<'tcx> {
}
}

/// The full crate name should use the Codegen Unit builder to include full name resolution,
/// for example, the versioning information if a build requires two different versions
/// of the same crate.
pub fn full_crate_name(tcx: TyCtxt<'tcx>) -> String {
format!(
"{}::{}",
CodegenUnitNameBuilder::new(tcx).build_cgu_name(
LOCAL_CRATE,
&[] as &[String; 0],
None as Option<String>
),
tcx.crate_name(LOCAL_CRATE)
)
}

//TODO: These were moved from hooks.rs, where they didn't have a goto context. Normalize them.
pub fn sig_of_instance<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::FnSig<'tcx> {
let ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
Expand Down
12 changes: 11 additions & 1 deletion scripts/rmc-regression.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

Expand Down Expand Up @@ -30,3 +30,13 @@ $SCRIPT_DIR/std-lib-regression.sh

# Check codegen of firecracker
$SCRIPT_DIR/codegen-firecracker.sh

# Check that we can use RMC on crates with a diamond dependency graph,
# with two different versions of the same crate.
#
# dependency1
# / \ v0.1.0
# main dependency3
# \ / v0.1.1
# dependency2
./src/test/rmc-dependency-test/diamond-dependency/run-dependency-test.sh
11 changes: 11 additions & 0 deletions src/test/rmc-dependency-test/dependency3/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

[package]
name = "dependency3"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
25 changes: 25 additions & 0 deletions src/test/rmc-dependency-test/dependency3/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR MIT

pub struct Foo {
x: i32,
}

// Export a function that takes a struct type which differs between this crate
// and the other vesion
pub fn take_foo(foo: &Foo) -> i32 {
foo.x
}

pub fn give_foo() -> Foo {
Foo { x: 1 }
}

pub fn get_int() -> i32 {
// Use a constant to force an MIR GlobalAllocation::Memory.
// Use a non-i32 so there will be a conflict between this
// version and the other version. The constant is also a
// different value than the other version of this dependency.
let one = &(1 as i8);
return *one as i32
}
5 changes: 5 additions & 0 deletions src/test/rmc-dependency-test/diamond-dependency/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

[workspace]
members = ["main", "dependency1", "dependency2", "dependency3"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

[package]
name = "dependency1"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
dependency3 = { path = "../dependency3" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR MIT

use dependency3;

pub fn delegate_get_int() -> i32 {
dependency3::get_int()
}

pub fn delegate_use_struct() -> i32 {
let foo = dependency3::give_foo();
dependency3::take_foo(&foo)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

[package]
name = "dependency2"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
dependency3 = { path = "../../dependency3" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR MIT

use dependency3;

pub fn delegate_get_int() -> i32 {
dependency3::get_int()
}

pub fn delegate_use_struct() -> i32 {
let foo = dependency3::give_foo();
dependency3::take_foo(&foo)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

[package]
name = "dependency3"
version = "0.1.1"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR MIT

pub struct Foo {
x: i32,
// This field only in this version.
y: i32,
}

// Export a function that takes a struct type which differs between this crate
// and the other vesion.
pub fn take_foo(foo: &Foo) -> i32 {
foo.x + foo.y
}

pub fn give_foo() -> Foo {
Foo { x: 1, y: 2 }
}

pub fn get_int() -> i32 {
// Use a constant to force an MIR GlobalAllocation::Memory
let zero = &0;
return *zero
}
13 changes: 13 additions & 0 deletions src/test/rmc-dependency-test/diamond-dependency/main/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

[package]
name = "main"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
dependency1 = { path = "../dependency1" }
dependency2 = { path = "../dependency2" }
14 changes: 14 additions & 0 deletions src/test/rmc-dependency-test/diamond-dependency/main/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR MIT

use dependency1;
use dependency2;

#[no_mangle]
fn harness() {
assert!(dependency1::delegate_get_int() == 0);
assert!(dependency2::delegate_get_int() == 1);

assert!(dependency1::delegate_use_struct() == 3);
assert!(dependency2::delegate_use_struct() == 1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

# Compile crates with RMC backend
cd $(dirname $0)
rm -rf build
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does cargo rmc not work

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it fails with:

rmc (dependencies) $ ./src/test/rmc-dependency-test/diamond-dependency/run-dependency-test.sh
ERROR: Unexpected number of json outputs: 5

It seems like the script for it assumes a single symbol table output, but here we get one per dependency and main.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets file a ticket for that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CARGO_TARGET_DIR=build RUST_BACKTRACE=1 RUSTFLAGS="-Z codegen-backend=gotoc --cfg=rmc" RUSTC=rmc-rustc cargo build

# Convert from JSON to Gotoc
cd build/debug/deps/
ls *.json | xargs symtab2gb

# Add the entry point and remove unused functions
goto-cc --function harness *.out -o a.out
goto-instrument --drop-unused-functions a.out b.out

# Run the solver
RESULT="/tmp/dependency_test_result.txt"
cbmc b.out &> $RESULT
if grep -q "VERIFICATION SUCCESSFUL" $RESULT; then
cat $RESULT
echo "Successful dependency test"
exit 0
else
cat $RESULT
echo "Failed dependency test"
exit 1
fi