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
4 changes: 3 additions & 1 deletion .github/workflows/rmc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ jobs:
export RUST_BACKTRACE=1
./x.py build -i --stage 1 library/std

- name: Build RMC Library
run: bash -x ./scripts/setup/build_rmc_lib.sh
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there any advantage to having -x written here and not in the script itself?

Copy link
Copy Markdown
Contributor Author

@celinval celinval Oct 29, 2021

Choose a reason for hiding this comment

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

I was wondering if this script will be helpful for users to build RMC library. In this case, we can keep the trace turned off by default, but still turn them on in the CI. What do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Makes sense.


- name: Execute RMC regression
run: ./scripts/rmc-regression.sh


- name: Install dashboard dependencies
if: ${{ matrix.os == 'ubuntu-20.04' && github.event_name == 'push' && startsWith('refs/heads/main', github.ref) }}
run: ./scripts/setup/install_dashboard_deps.sh
Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3310,6 +3310,10 @@ dependencies = [
"rls-span",
]

[[package]]
name = "rmc"
version = "0.1.0"

[[package]]
name = "rust-demangler"
version = "0.0.1"
Expand Down
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"compiler/rustc",
"library/std",
"library/test",
"library/rmc",
"src/rustdoc-json-types",
"src/tools/cargotest",
"src/tools/clippy",
Expand Down Expand Up @@ -55,7 +56,9 @@ exclude = [
# stdarch has its own Cargo workspace
"library/stdarch",
# dependency tests have their own workspace
"src/test/rmc-dependency-test/dependency3"
"src/test/rmc-dependency-test/dependency3",
# cargo rmc tests should also have their own workspace
"src/test/cargo-rmc"
]

[profile.release.package.compiler_builtins]
Expand Down
25 changes: 14 additions & 11 deletions compiler/rustc_codegen_rmc/src/compiler_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ impl CodegenBackend for GotocCodegenBackend {

fn link(
&self,
_sess: &Session,
sess: &Session,
codegen_results: Box<dyn Any>,
outputs: &OutputFilenames,
) -> Result<(), ErrorReported> {
Expand All @@ -157,18 +157,21 @@ impl CodegenBackend for GotocCodegenBackend {
.downcast::<GotocCodegenResult>()
.expect("in link: codegen_results is not a GotocCodegenResult");

// "path.o"
let base_filename = outputs.path(OutputType::Object);
// No output should be generated if user selected no_codegen.
if !sess.opts.debugging_opts.no_codegen && sess.opts.output_types.should_codegen() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does this need to be in the same PR?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes. The regression will fail if this is not here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I can submit a separate PR and merge it first if that makes more sense.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

// "path.o"
let base_filename = outputs.path(OutputType::Object);

let symtab_filename = base_filename.with_extension("symtab.json");
debug!("output to {:?}", symtab_filename);
let mut out_file = ::std::fs::File::create(&symtab_filename).unwrap();
write!(out_file, "{}", result.symtab.to_irep().to_json().pretty().to_string()).unwrap();
let symtab_filename = base_filename.with_extension("symtab.json");
debug!("output to {:?}", symtab_filename);
let mut out_file = ::std::fs::File::create(&symtab_filename).unwrap();
write!(out_file, "{}", result.symtab.to_irep().to_json().pretty().to_string()).unwrap();

let type_map_filename = base_filename.with_extension("type_map.json");
debug!("type_map to {:?}", type_map_filename);
let mut out_file = ::std::fs::File::create(&type_map_filename).unwrap();
write!(out_file, "{}", result.type_map.to_json().pretty().to_string()).unwrap();
let type_map_filename = base_filename.with_extension("type_map.json");
debug!("type_map to {:?}", type_map_filename);
let mut out_file = ::std::fs::File::create(&type_map_filename).unwrap();
write!(out_file, "{}", result.type_map.to_json().pretty().to_string()).unwrap();
}

Ok(())
}
Expand Down
54 changes: 33 additions & 21 deletions compiler/rustc_codegen_rmc/src/overrides/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@ use super::stubs::{HashMapStub, VecStub};
use crate::utils::{instance_name_is, instance_name_starts_with};
use crate::GotocCtx;
use cbmc::goto_program::{BuiltinFn, Expr, Location, Stmt, Symbol, Type};
use rustc_hir::definitions::DefPathDataName;
use rustc_middle::mir::{BasicBlock, Place};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Instance, InstanceDef, Ty, TyCtxt};
use rustc_span::Span;
use std::rc::Rc;
use tracing::debug;
use tracing::{debug, warn};

pub trait GotocTypeHook<'tcx> {
fn hook_applies(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool;
Expand Down Expand Up @@ -66,19 +65,29 @@ fn output_of_instance_is_never<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>
}
}

fn matches_function(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, attr_name: &str) -> bool {
let attr_sym = rustc_span::symbol::Symbol::intern(attr_name);
if let Some(attr_id) = tcx.all_diagnostic_items(()).name_to_id.get(&attr_sym) {
if instance.def.def_id() == *attr_id {
debug!("matched: {:?} {:?}", attr_id, attr_sym);
return true;
}
}
false
}

struct ExpectFail;
impl<'tcx> GotocHook<'tcx> for ExpectFail {
fn hook_applies(&self, tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
let def_path = tcx.def_path(instance.def.def_id());
if let Some(data) = def_path.data.last() {
match data.data.name() {
DefPathDataName::Named(name) => {
return name.to_string().starts_with("__VERIFIER_expect_fail");
}
DefPathDataName::Anon { .. } => (),
}
// Deprecate old __VERIFIER notation that doesn't respect rust naming conventions.
// Complete removal is tracked here: https://github.com/model-checking/rmc/issues/599
if instance_name_starts_with(tcx, instance, "__VERIFIER_expect_fail") {
warn!(
"The function __VERIFIER_expect_fail is deprecated. Use rmc::expect_fail instead"
);
return true;
}
false
matches_function(tcx, instance, "RmcExpectFail")
}

fn handle(
Expand Down Expand Up @@ -109,16 +118,13 @@ impl<'tcx> GotocHook<'tcx> for ExpectFail {
struct Assume;
impl<'tcx> GotocHook<'tcx> for Assume {
fn hook_applies(&self, tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
let def_path = tcx.def_path(instance.def.def_id());
if let Some(data) = def_path.data.last() {
match data.data.name() {
DefPathDataName::Named(name) => {
return name.to_string().starts_with("__VERIFIER_assume");
}
DefPathDataName::Anon { .. } => (),
}
// Deprecate old __VERIFIER notation that doesn't respect rust naming conventions.
// Complete removal is tracked here: https://github.com/model-checking/rmc/issues/599
if instance_name_starts_with(tcx, instance, "__VERIFIER_assume") {
warn!("The function __VERIFIER_assume is deprecated. Use rmc::assume instead");
return true;
}
false
matches_function(tcx, instance, "RmcAssume")
}

fn handle(
Expand Down Expand Up @@ -149,7 +155,13 @@ struct Nondet;

impl<'tcx> GotocHook<'tcx> for Nondet {
fn hook_applies(&self, tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
instance_name_starts_with(tcx, instance, "__nondet")
// Deprecate old __nondet since it doesn't match rust naming conventions.
// Complete removal is tracked here: https://github.com/model-checking/rmc/issues/599
if instance_name_starts_with(tcx, instance, "__nondet") {
warn!("The function __nondet is deprecated. Use rmc::nondet instead");
return true;
}
matches_function(tcx, instance, "RmcNonDet")
}

fn handle(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_rmc/src/overrides/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT

//! This module provides a mechanism which RMC can use to override standard codegen.
//! For example, we the RMC provides pseudo-functions, such as __VERIFIER_assume().
//! For example, we the RMC provides pseudo-functions, such as rmc::assume().
//! These functions should not be codegenned as MIR.
//! Instead, we use a "hook" to generate the correct CBMC intrinsic.

Expand Down
10 changes: 10 additions & 0 deletions library/rmc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

[package]
name = "rmc"
version = "0.1.0"
edition = "2018"
license = "MIT OR Apache-2.0"

[dependencies]
53 changes: 53 additions & 0 deletions library/rmc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR MIT
#![feature(rustc_attrs)] // Used for rustc_diagnostic_item.

/// Creates an assumption that will be valid after this statement run. Note that the assumption
/// will only be applied for paths that follow the assumption. If the assumption doesn't hold, the
/// program will exit successfully.
///
/// # Example:
///
/// The code snippet below should never panic.
///
/// ```rust
/// let i : i32 = rmc::nondet();
/// rmc::assume(i > 10);
/// if i < 0 {
/// panic!("This will never panic");
/// }
/// ```
///
/// The following code may panic though:
///
/// ```rust
/// let i : i32 = rmc::nondet();
/// assert!(i < 0, "This may panic and verification should fail.");
/// rmc::assume(i > 10);
/// ```
#[inline(never)]
#[rustc_diagnostic_item = "RmcAssume"]
pub fn assume(_cond: bool) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For a better docs and IDE experience, it would be preferable to do something like:

pub fn assume(cond: bool) {
    let _ = cond;
}

Same goes for the other arguments.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure. I'll fix this next time I push some updates to this crate. Thanks for the suggestion.


/// This creates an unconstrained value of type `T`. You can assign the return value of this
/// function to a variable that you want to make symbolic.
///
/// # Example:
///
/// In the snippet below, we are verifying the behavior of the function `fn_under_verification`
/// under all possible i32 input values.
///
/// ```rust
/// let inputA = rmc::nondet::<i32>();
/// fn_under_verification(inputA);
/// ```
#[inline(never)]
#[rustc_diagnostic_item = "RmcNonDet"]
pub fn nondet<T>() -> T {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This really needs to be marked as unsafe as callers need to ensure all of the type's invariants are met.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have pushed this code already, but I created #607 to capture the work to fix this. Thanks

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

unimplemented!("RMC nondet")
}

/// Function used in tests for cases where the condition is not always true.
#[inline(never)]
#[rustc_diagnostic_item = "RmcExpectFail"]
pub fn expect_fail(_cond: bool, _message: &str) {}
6 changes: 5 additions & 1 deletion scripts/codegen-firecracker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ echo
# At the moment, we only test codegen for the virtio module
cd $RMC_DIR/firecracker/src/devices/src/virtio/
# Disable warnings until https://github.com/model-checking/rmc/issues/573 is fixed
RUSTC_LOG=error RUST_BACKTRACE=1 RUSTFLAGS="-Z trim-diagnostic-paths=no -Z codegen-backend=gotoc --cfg=rmc" RUSTC=rmc-rustc cargo build --target x86_64-unknown-linux-gnu
export RUSTC_LOG=error
export RUST_BACKTRACE=1
export RUSTFLAGS=$(${SCRIPT_DIR}/rmc-rustc --rmc-flags)
export RUSTC=$(${SCRIPT_DIR}/rmc-rustc --rmc-path)
cargo build --target x86_64-unknown-linux-gnu

echo
echo "Finished Firecracker codegen regression successfully..."
Expand Down
61 changes: 52 additions & 9 deletions scripts/rmc-rustc
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,62 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

# Usage:
# rmc-rustc (--rmc-flags | --rmc-path)
# - This will print the configurations used to run rmc version of rustc.
# rmc-rustc RUSTC_OPTIONS
# - This will run RUSTC with RMC flags + the given RUSTC_OPTIONS
set -eu

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
REPO_DIR="$(dirname $SCRIPT_DIR)"

shopt -s nullglob
RMC_CANDIDATES=("$REPO_DIR"/build/*/stage1/bin/rustc)
get_rmc_path() {
shopt -s nullglob
RMC_CANDIDATES=("$REPO_DIR"/build/*/stage1/bin/rustc)

if [[ ${#RMC_CANDIDATES[@]} -ne 1 ]]; then
echo "ERROR: Could not find RMC binary."
echo "Looked for: $REPO_DIR/build/*/stage1/bin/rustc"
echo "Was RMC successfully built first?"
exit 1
fi
if [[ ${#RMC_CANDIDATES[@]} -ne 1 ]]; then
echo "ERROR: Could not find RMC binary."
echo "Looked for: $REPO_DIR/build/*/stage1/bin/rustc"
echo "Was RMC successfully built first?"
exit 1
fi
echo ${RMC_CANDIDATES[0]}
}

get_rmc_lib_path() {
if [ -z "${RMC_LIB_PATH:-""}" ]
then
RMC_LIB_CANDIDATES=("$REPO_DIR"/target/*/librmc.rlib)
if [[ ${#RMC_LIB_CANDIDATES[@]} -ne 1 ]]; then
echo "ERROR: Could not find RMC library."
echo "Looked for: \"$REPO_DIR/target/*/librmc.rlib\""
echo "Was RMC library successfully built first?"
exit 1
fi
echo $(dirname ${RMC_LIB_CANDIDATES[0]})
else
echo ${RMC_LIB_PATH}
fi
}

RMC_PATH=$(get_rmc_path)

"${RMC_CANDIDATES[0]}" "$@"
RMC_FLAGS="--crate-type=lib \
-Z codegen-backend=gotoc \
-Z trim-diagnostic-paths=no \
-Z human_readable_cgu_names \
--cfg=rmc \
-L $(get_rmc_lib_path) \
--extern rmc"

if [ "${1:-''}" == "--rmc-flags" ]
then
echo ${RMC_FLAGS}
elif [ "${1:-''}" == "--rmc-path" ]
then
echo ${RMC_PATH}
else
# Execute rmc
"${RMC_PATH}" ${RMC_FLAGS} "$@"
fi
13 changes: 7 additions & 6 deletions scripts/rmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,9 @@ def run_cmd(

def rustc_flags(mangler, symbol_table_passes):
flags = [
"-Z", "codegen-backend=gotoc",
"-Z", "trim-diagnostic-paths=no",
"-Z", f"symbol-mangling-version={mangler}",
"-Z", f"symbol_table_passes={' '.join(symbol_table_passes)}",
"-Z", "human_readable_cgu_names",
f"--cfg={RMC_CFG}"]
]
if "RUSTFLAGS" in os.environ:
flags += os.environ["RUSTFLAGS"].split(" ")
return flags
Expand All @@ -176,7 +173,7 @@ def compile_single_rust_file(
atexit.register(delete_file, output_filename)
atexit.register(delete_file, base + ".type_map.json")

build_cmd = [RMC_RUSTC_EXE, "--crate-type=lib"] + rustc_flags(mangler, symbol_table_passes)
build_cmd = [RMC_RUSTC_EXE] + rustc_flags(mangler, symbol_table_passes)

if use_abs:
build_cmd += ["-Z", "force-unstable-if-unmarked=yes",
Expand All @@ -199,10 +196,14 @@ def cargo_build(crate, target_dir, verbose=False, debug=False, mangler="v0", dry
build_cmd = ["cargo", "build", "--lib", "--target-dir", str(target_dir)]
build_env = {"RUSTFLAGS": " ".join(rustflags),
"RUSTC": RMC_RUSTC_EXE,
"PATH": os.environ["PATH"],
"PATH": os.environ["PATH"]
}
if debug:
add_rmc_rustc_debug_to_env(build_env)
if verbose:
build_cmd.append("-v")
if dry_run:
print("{}".format(build_env))
return run_cmd(build_cmd, env=build_env, cwd=crate, label="build", verbose=verbose, debug=debug, dry_run=dry_run)

# Adds information about unwinding to the RMC output
Expand Down
14 changes: 14 additions & 0 deletions scripts/setup/build_rmc_lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR MIT

set -o errexit
set -o nounset

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
SCRIPTS_DIR="$(dirname $SCRIPT_DIR)"
REPO_DIR="$(dirname $SCRIPTS_DIR)"

export RUSTC=$(${SCRIPTS_DIR}/rmc-rustc --rmc-path)
cargo build --manifest-path "${REPO_DIR}/library/rmc/Cargo.toml" $@

Loading