@@ -11,6 +11,7 @@ use std::ops::RangeInclusive;
11
11
12
12
use rustc_data_structures:: fx:: FxHashSet ;
13
13
use rustc_hir as hir;
14
+ use rustc_middle:: mir:: interpret:: { InterpError , InterpErrorInfo } ;
14
15
use rustc_middle:: ty;
15
16
use rustc_middle:: ty:: layout:: TyAndLayout ;
16
17
use rustc_span:: symbol:: { sym, Symbol } ;
@@ -24,43 +25,71 @@ use super::{
24
25
} ;
25
26
26
27
macro_rules! throw_validation_failure {
27
- ( $what: expr, $where: expr, $details: expr) => { {
28
- let mut msg = format!( "encountered {}" , $what) ;
29
- let where_ = & $where;
30
- if !where_. is_empty( ) {
31
- msg. push_str( " at " ) ;
32
- write_path( & mut msg, where_) ;
33
- }
34
- write!( & mut msg, ", but expected {}" , $details) . unwrap( ) ;
35
- throw_ub!( ValidationFailure ( msg) )
36
- } } ;
37
- ( $what: expr, $where: expr) => { {
28
+ ( $what: expr, $where: expr $( , $expected: expr ) ?) => { {
38
29
let mut msg = format!( "encountered {}" , $what) ;
39
30
let where_ = & $where;
40
31
if !where_. is_empty( ) {
41
32
msg. push_str( " at " ) ;
42
33
write_path( & mut msg, where_) ;
43
34
}
35
+ $( write!( & mut msg, ", but expected {}" , $expected) . unwrap( ) ; ) ?
44
36
throw_ub!( ValidationFailure ( msg) )
45
37
} } ;
46
38
}
47
39
40
+ /// Returns a validation failure for any Err value of $e.
41
+ // FIXME: Replace all usages of try_validation! with try_validation_pat!.
48
42
macro_rules! try_validation {
49
- ( $e: expr, $what: expr, $where: expr, $details: expr) => { {
50
- match $e {
51
- Ok ( x) => x,
52
- // We re-throw the error, so we are okay with allocation:
53
- // this can only slow down builds that fail anyway.
54
- Err ( _) => throw_validation_failure!( $what, $where, $details) ,
55
- }
43
+ ( $e: expr, $what: expr, $where: expr $( , $expected: expr ) ?) => { {
44
+ try_validation_pat!( $e, $where, {
45
+ _ => { "{}" , $what } $( expected { "{}" , $expected } ) ?,
46
+ } )
56
47
} } ;
57
-
58
- ( $e: expr, $what: expr, $where: expr) => { {
48
+ }
49
+ /// Like try_validation, but will throw a validation error if any of the patterns in $p are
50
+ /// matched. Other errors are passed back to the caller, unchanged. This lets you use the patterns
51
+ /// as a kind of validation blacklist:
52
+ ///
53
+ /// ```
54
+ /// let v = try_validation_pat!(some_fn(), some_path, {
55
+ /// Foo | Bar | Baz => { "some failure" },
56
+ /// });
57
+ /// // Failures that match $p are thrown up as validation errors, but other errors are passed back
58
+ /// // unchanged.
59
+ /// ```
60
+ ///
61
+ /// An additional expected parameter can also be added to the failure message:
62
+ ///
63
+ /// ```
64
+ /// let v = try_validation_pat!(some_fn(), some_path, {
65
+ /// Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" },
66
+ /// });
67
+ /// ```
68
+ ///
69
+ /// An additional nicety is that both parameters actually take format args, so you can just write
70
+ /// the format string in directly:
71
+ ///
72
+ /// ```
73
+ /// let v = try_validation_pat!(some_fn(), some_path, {
74
+ /// Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value },
75
+ /// });
76
+ /// ```
77
+ ///
78
+ macro_rules! try_validation_pat {
79
+ ( $e: expr, $where: expr, { $( $p: pat ) |+ =>
80
+ { $( $what_fmt: expr ) ,+ } $( expected { $( $expected_fmt: expr ) ,+ } ) ? $( , ) ?} ) => { {
59
81
match $e {
60
82
Ok ( x) => x,
61
- // We re-throw the error, so we are okay with allocation:
62
- // this can only slow down builds that fail anyway.
63
- Err ( _) => throw_validation_failure!( $what, $where) ,
83
+ // We catch the error and turn it into a validation failure. We are okay with
84
+ // allocation here as this can only slow down builds that fail anyway.
85
+ $( Err ( InterpErrorInfo { kind: $p, .. } ) ) |+ =>
86
+ throw_validation_failure!(
87
+ format_args!( $( $what_fmt ) ,+) ,
88
+ $where
89
+ $( , format_args!( $( $expected_fmt ) ,+) ) ?
90
+ ) ,
91
+ #[ allow( unreachable_patterns) ]
92
+ Err ( e) => Err :: <!, _>( e) ?,
64
93
}
65
94
} } ;
66
95
}
@@ -492,11 +521,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
492
521
// We are conservative with undef for integers, but try to
493
522
// actually enforce the strict rules for raw pointers (mostly because
494
523
// that lets us re-use `ref_to_mplace`).
495
- let place = try_validation ! (
496
- self . ecx. ref_to_mplace( self . ecx. read_immediate( value) ?) ,
497
- "uninitialized raw pointer" ,
498
- self . path
499
- ) ;
524
+ let place = try_validation_pat ! ( self . ecx. ref_to_mplace( self . ecx. read_immediate( value) ?) , self . path, {
525
+ err_ub!( InvalidUndefBytes ( ..) ) => { "uninitialized raw pointer" } ,
526
+ } ) ;
500
527
if place. layout . is_unsized ( ) {
501
528
self . check_wide_ptr_meta ( place. meta , place. layout ) ?;
502
529
}
@@ -800,7 +827,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
800
827
801
828
throw_validation_failure ! ( "uninitialized bytes" , self . path)
802
829
}
803
- // Other errors shouldn't be possible
830
+ // Propagate upwards (that will also check for unexpected errors).
804
831
_ => return Err ( err) ,
805
832
}
806
833
}
@@ -843,9 +870,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
843
870
// Run it.
844
871
match visitor. visit_value ( op) {
845
872
Ok ( ( ) ) => Ok ( ( ) ) ,
846
- // We should only get validation errors here. Avoid other errors as
847
- // those do not show *where* in the value the issue lies.
873
+ // Pass through validation failures.
848
874
Err ( err) if matches ! ( err. kind, err_ub!( ValidationFailure { .. } ) ) => Err ( err) ,
875
+ // Also pass through InvalidProgram, those just indicate that we could not
876
+ // validate and each caller will know best what to do with them.
877
+ Err ( err) if matches ! ( err. kind, InterpError :: InvalidProgram ( _) ) => Err ( err) ,
878
+ // Avoid other errors as those do not show *where* in the value the issue lies.
849
879
Err ( err) => bug ! ( "Unexpected error during validation: {}" , err) ,
850
880
}
851
881
}
0 commit comments