Skip to content

Commit edc7067

Browse files
Herman Venterzlandau
Herman Venter
authored andcommitted
Give warning if control might right reach std::intrinsics::unreachable (facebookexperimental#25)
1 parent af53f25 commit edc7067

File tree

6 files changed

+49
-13
lines changed

6 files changed

+49
-13
lines changed

.codecov.yml

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
ignore:
22
- tests/.*
3-
- src/main.rs
3+
- src/main.rs
4+
5+
coverage:
6+
range: 60..85
7+
round: down
8+
precision: 0

.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ before_script:
1717
# install linter
1818
- rustup component add clippy-preview
1919
# install code coverage tool
20-
- RUSTFLAGS="--cfg procmacro2_semver_exempt" cargo install cargo-tarpaulin || true
20+
- RUSTFLAGS="--cfg procmacro2_semver_exempt" cargo install --force cargo-tarpaulin || true
2121

2222
script:
2323
# Exit immediately if a command exits with a non-zero status.
@@ -37,6 +37,6 @@ script:
3737
- RUSTC_WRAPPER=mirai cargo build
3838
- cargo uninstall mirai
3939
- cargo clean -p mirai
40-
- cargo tarpaulin -v --skip-clean --out Xml || true
40+
- cargo tarpaulin -v --out Xml || true
4141
- bash <(curl -s https://codecov.io/bash)
4242

src/callbacks.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,15 @@ impl<'a> CompilerCalls<'a> for MiraiCallbacks {
116116
/// At this point the compiler is ready to tell us all it knows and we can proceed to do abstract
117117
/// interpretation of all of the functions that will end up in the compiler output.
118118
fn after_analysis(state: &mut driver::CompileState, output_directory: &mut PathBuf) {
119+
let session = state.session;
119120
let tcx = state.tcx.unwrap();
120121
output_directory.set_file_name(".summary_store");
121122
output_directory.set_extension("rocksdb");
122123
let summary_store_path = String::from(output_directory.to_str().unwrap());
123124
info!("storing summaries at {}", summary_store_path);
124125
let mut persistent_summary_cache =
125126
summaries::PersistentSummaryCache::new(&tcx, summary_store_path);
126-
let mut constant_value_cache = ConstantValueCache::new();
127+
let mut constant_value_cache = ConstantValueCache::default();
127128
for def_id in tcx.body_owners() {
128129
{
129130
let name = persistent_summary_cache.get_summary_key_for(def_id);
@@ -139,6 +140,7 @@ fn after_analysis(state: &mut driver::CompileState, output_directory: &mut PathB
139140
let mut unwind_condition: Option<AbstractValue> = None;
140141
{
141142
let mut mir_visitor = MirVisitor {
143+
session,
142144
tcx,
143145
def_id,
144146
mir,

src/constant_value.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
// LICENSE file in the root directory of this source tree.
55

66
use rustc::hir::def_id::DefId;
7+
use rustc::ty::TyCtxt;
78
use std::collections::HashMap;
89
use summaries::PersistentSummaryCache;
10+
use utils::is_rust_intrinsic;
911

1012
/// Abstracts over constant values referenced in MIR and adds information
1113
/// that is useful for the abstract interpreter. More importantly, this
@@ -29,12 +31,13 @@ impl ConstantValue {
2931
/// Returns a constant value that is a reference to a function
3032
pub fn for_function(
3133
def_id: DefId,
34+
tcx: &TyCtxt,
3235
summary_cache: &mut PersistentSummaryCache,
3336
) -> ConstantValue {
3437
let summary_cache_key = summary_cache.get_summary_key_for(def_id);
3538
// todo: include the def_id in the result
3639
ConstantValue::Function {
37-
is_intrinsic: false,
40+
is_intrinsic: is_rust_intrinsic(def_id, tcx),
3841
summary_cache_key: summary_cache_key.to_owned(),
3942
}
4043
}
@@ -59,11 +62,12 @@ impl ConstantValueCache {
5962
pub fn get_function_constant_for(
6063
&mut self,
6164
def_id: DefId,
65+
tcx: &TyCtxt,
6266
summary_cache: &mut PersistentSummaryCache,
6367
) -> &ConstantValue {
6468
self.cache
6569
.entry(def_id)
66-
.or_insert_with(|| ConstantValue::for_function(def_id, summary_cache))
70+
.or_insert_with(|| ConstantValue::for_function(def_id, tcx, summary_cache))
6771
}
6872

6973
/// Does an expensive check to see if the given function is std::intrinsics::unreachable.
@@ -84,7 +88,7 @@ impl ConstantValueCache {
8488
if result {
8589
self.std_intrinsics_unreachable_function = Some(fun.clone());
8690
};
87-
true
91+
result
8892
})
8993
}
9094
}

src/visitors.rs

+23-6
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ use abstract_domains::{AbstractDomains, ExpressionDomain};
77
use abstract_value::{AbstractValue, Path};
88
use constant_value::{ConstantValue, ConstantValueCache};
99
use rpds::{HashTrieMap, List};
10-
use rustc::ty::{Const, Ty, TyCtxt, TyKind};
10+
use rustc::session::Session;
11+
use rustc::ty::{Const, Ty, TyCtxt, TyKind, UserTypeAnnotationIndex};
1112
use rustc::{hir, mir};
1213
use std::borrow::Borrow;
1314
use summaries::PersistentSummaryCache;
1415
use syntax_pos;
1516

1617
/// Holds the state for the MIR test visitor.
1718
pub struct MirVisitor<'a, 'b: 'a, 'tcx: 'b> {
19+
pub session: &'tcx Session,
1820
pub tcx: TyCtxt<'b, 'tcx, 'tcx>,
1921
pub def_id: hir::def_id::DefId,
2022
pub mir: &'a mir::Mir<'tcx>,
@@ -276,7 +278,20 @@ impl<'a, 'b: 'a, 'tcx: 'b> MirVisitor<'a, 'b, 'tcx> {
276278
from_hir_call: bool,
277279
) {
278280
debug!("default visit_call(func: {:?}, args: {:?}, destination: {:?}, cleanup: {:?}, from_hir_call: {:?})", func, args, destination, cleanup, from_hir_call);
279-
self.visit_operand(func);
281+
let func_to_call = self.visit_operand(func);
282+
if let ExpressionDomain::CompileTimeConstant(fun) = func_to_call.value.expression_domain {
283+
if self
284+
.constant_value_cache
285+
.check_if_std_intrinsics_unreachable_function(&fun)
286+
{
287+
let span = self.current_span;
288+
let mut err = self.session.struct_span_warn(
289+
span,
290+
"Control might reach a call to std::intrinsics::unreachable",
291+
);
292+
err.emit();
293+
}
294+
}
280295
}
281296

282297
/// Jump to the target if the condition has the expected value,
@@ -474,7 +489,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> MirVisitor<'a, 'b, 'tcx> {
474489
fn visit_constant(
475490
&mut self,
476491
ty: Ty,
477-
user_ty: Option<mir::UserTypeAnnotation>,
492+
user_ty: Option<UserTypeAnnotationIndex>,
478493
literal: &Const,
479494
) -> &ConstantValue {
480495
debug!(
@@ -498,8 +513,10 @@ impl<'a, 'b: 'a, 'tcx: 'b> MirVisitor<'a, 'b, 'tcx> {
498513
/// let bar = foo; // bar: fn() -> i32 {foo}
499514
/// ```
500515
fn visit_function_reference(&mut self, def_id: hir::def_id::DefId) -> &ConstantValue {
501-
&mut self
502-
.constant_value_cache
503-
.get_function_constant_for(def_id, &mut self.summary_cache)
516+
&mut self.constant_value_cache.get_function_constant_for(
517+
def_id,
518+
&self.tcx,
519+
&mut self.summary_cache,
520+
)
504521
}
505522
}

tests/run-pass/unreachable.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
// Copyright (c) Facebook, Inc. and its affiliates.
2+
//
3+
// This source code is licensed under the MIT license found in the
4+
// LICENSE file in the root directory of this source tree.
5+
//
6+
7+
// A test that calls std::intrinsics::unreachable unconditionally.
8+
19
#![feature(core_intrinsics)]
210
#![allow(unused)]
311

0 commit comments

Comments
 (0)