@@ -11,9 +11,10 @@ use serde::{Serialize, Serializer, ser::SerializeStruct};
1111use stable_mir:: mir:: mono:: Instance ;
1212use stable_mir:: mir:: visit:: { Location , PlaceContext , PlaceRef } ;
1313use stable_mir:: mir:: {
14- BasicBlock , Body , MirVisitor , Mutability , ProjectionElem , Safety , Terminator , TerminatorKind ,
14+ BasicBlock , Body , CastKind , MirVisitor , Mutability , NonDivergingIntrinsic , ProjectionElem ,
15+ Rvalue , Safety , Statement , StatementKind , Terminator , TerminatorKind ,
1516} ;
16- use stable_mir:: ty:: { AdtDef , AdtKind , FnDef , GenericArgs , MirConst , RigidTy , Ty , TyKind } ;
17+ use stable_mir:: ty:: { Abi , AdtDef , AdtKind , FnDef , GenericArgs , MirConst , RigidTy , Ty , TyKind } ;
1718use stable_mir:: visitor:: { Visitable , Visitor } ;
1819use stable_mir:: { CrateDef , CrateItem } ;
1920use std:: collections:: { HashMap , HashSet } ;
@@ -23,7 +24,7 @@ use std::path::{Path, PathBuf};
2324#[ derive( Clone , Debug ) ]
2425pub struct OverallStats {
2526 /// The key and value of each counter.
26- counters : Vec < ( & ' static str , usize ) > ,
27+ pub counters : Vec < ( & ' static str , usize ) > ,
2728 /// TODO: Group stats per function.
2829 fn_stats : HashMap < CrateItem , FnStats > ,
2930}
@@ -35,6 +36,12 @@ struct FnStats {
3536 has_unsafe_ops : Option < bool > ,
3637 has_unsupported_input : Option < bool > ,
3738 has_loop_or_iterator : Option < bool > ,
39+ /// How many degrees of separation to unsafe code if any?
40+ /// - `None` if this function is indeed safe.
41+ /// - 0 if this function contains unsafe code (including invoking unsafe fns).
42+ /// - 1 if this function calls a safe abstraction.
43+ /// - 2+ if this function calls other functions that call safe abstractions.
44+ unsafe_distance : Option < usize > ,
3845}
3946
4047impl FnStats {
@@ -45,6 +52,7 @@ impl FnStats {
4552 has_unsafe_ops : None ,
4653 has_unsupported_input : None ,
4754 has_loop_or_iterator : None ,
55+ unsafe_distance : None ,
4856 }
4957 }
5058}
@@ -232,24 +240,24 @@ impl OverallStats {
232240
233241macro_rules! fn_props {
234242 ( $( #[ $attr: meta] ) *
235- struct $name: ident {
243+ $vis : vis struct $name: ident {
236244 $(
237245 $( #[ $prop_attr: meta] ) *
238246 $prop: ident,
239247 ) +
240248 } ) => {
241249 #[ derive( Debug ) ]
242- struct $name {
250+ $vis struct $name {
243251 fn_name: String ,
244252 $( $( #[ $prop_attr] ) * $prop: usize , ) +
245253 }
246254
247255 impl $name {
248- const fn num_props( ) -> usize {
256+ pub const fn num_props( ) -> usize {
249257 [ $( stringify!( $prop) , ) +] . len( )
250258 }
251259
252- fn new( fn_name: String ) -> Self {
260+ pub fn new( fn_name: String ) -> Self {
253261 Self { fn_name, $( $prop: 0 , ) +}
254262 }
255263 }
@@ -369,7 +377,7 @@ impl Visitor for TypeVisitor<'_> {
369377 }
370378}
371379
372- fn dump_csv < T : Serialize > ( mut out_path : PathBuf , data : & [ T ] ) {
380+ pub ( crate ) fn dump_csv < T : Serialize > ( mut out_path : PathBuf , data : & [ T ] ) {
373381 out_path. set_extension ( "csv" ) ;
374382 info ( format ! ( "Write file: {out_path:?}" ) ) ;
375383 let mut writer = WriterBuilder :: new ( ) . delimiter ( b';' ) . from_path ( & out_path) . unwrap ( ) ;
@@ -379,17 +387,23 @@ fn dump_csv<T: Serialize>(mut out_path: PathBuf, data: &[T]) {
379387}
380388
381389fn_props ! {
382- struct FnUnsafeOperations {
390+ pub struct FnUnsafeOperations {
383391 inline_assembly,
384392 /// Dereference a raw pointer.
385393 /// This is also counted when we access a static variable since it gets translated to a raw pointer.
386394 unsafe_dereference,
387- /// Call an unsafe function or method.
395+ /// Call an unsafe function or method including C-FFI .
388396 unsafe_call,
389397 /// Access or modify a mutable static variable.
390398 unsafe_static_access,
391399 /// Access fields of unions.
392400 unsafe_union_access,
401+ /// Invoke external functions (this is a subset of `unsafe_call`.
402+ extern_call,
403+ /// Transmute operations.
404+ transmute,
405+ /// Cast raw pointer to reference.
406+ unsafe_cast,
393407 }
394408}
395409
@@ -419,9 +433,21 @@ impl MirVisitor for BodyVisitor<'_> {
419433 fn visit_terminator ( & mut self , term : & Terminator , location : Location ) {
420434 match & term. kind {
421435 TerminatorKind :: Call { func, .. } => {
422- let fn_sig = func. ty ( self . body . locals ( ) ) . unwrap ( ) . kind ( ) . fn_sig ( ) . unwrap ( ) ;
423- if fn_sig. value . safety == Safety :: Unsafe {
436+ let TyKind :: RigidTy ( RigidTy :: FnDef ( fn_def, _) ) =
437+ func. ty ( self . body . locals ( ) ) . unwrap ( ) . kind ( )
438+ else {
439+ return self . super_terminator ( term, location) ;
440+ } ;
441+ let fn_sig = fn_def. fn_sig ( ) . skip_binder ( ) ;
442+ if fn_sig. safety == Safety :: Unsafe {
424443 self . props . unsafe_call += 1 ;
444+ if !matches ! (
445+ fn_sig. abi,
446+ Abi :: Rust | Abi :: RustCold | Abi :: RustCall | Abi :: RustIntrinsic
447+ ) && !fn_def. has_body ( )
448+ {
449+ self . props . extern_call += 1 ;
450+ }
425451 }
426452 }
427453 TerminatorKind :: InlineAsm { .. } => self . props . inline_assembly += 1 ,
@@ -430,6 +456,34 @@ impl MirVisitor for BodyVisitor<'_> {
430456 self . super_terminator ( term, location)
431457 }
432458
459+ fn visit_rvalue ( & mut self , rvalue : & Rvalue , location : Location ) {
460+ if let Rvalue :: Cast ( cast_kind, operand, ty) = rvalue {
461+ match cast_kind {
462+ CastKind :: Transmute => {
463+ self . props . transmute += 1 ;
464+ }
465+ _ => {
466+ let operand_ty = operand. ty ( self . body . locals ( ) ) . unwrap ( ) ;
467+ if ty. kind ( ) . is_ref ( ) && operand_ty. kind ( ) . is_raw_ptr ( ) {
468+ self . props . unsafe_cast += 1 ;
469+ }
470+ }
471+ }
472+ } ;
473+ self . super_rvalue ( rvalue, location) ;
474+ }
475+
476+ fn visit_statement ( & mut self , stmt : & Statement , location : Location ) {
477+ if matches ! (
478+ & stmt. kind,
479+ StatementKind :: Intrinsic ( NonDivergingIntrinsic :: CopyNonOverlapping ( _) )
480+ ) {
481+ // Treat this as invoking the copy intrinsic.
482+ self . props . unsafe_call += 1 ;
483+ }
484+ self . super_statement ( stmt, location)
485+ }
486+
433487 fn visit_projection_elem (
434488 & mut self ,
435489 place : PlaceRef ,
@@ -674,9 +728,9 @@ impl Recursion {
674728 }
675729}
676730
677- struct FnCallVisitor < ' a > {
678- body : & ' a Body ,
679- fns : Vec < FnDef > ,
731+ pub struct FnCallVisitor < ' a > {
732+ pub body : & ' a Body ,
733+ pub fns : Vec < FnDef > ,
680734}
681735
682736impl MirVisitor for FnCallVisitor < ' _ > {
0 commit comments