};
macro_rules! throw_validation_failure {
- ($what:expr, $where:expr, $details:expr) => {{
- let mut msg = format!("encountered {}", $what);
- let where_ = &$where;
- if !where_.is_empty() {
- msg.push_str(" at ");
- write_path(&mut msg, where_);
- }
- write!(&mut msg, ", but expected {}", $details).unwrap();
- throw_ub!(ValidationFailure(msg))
- }};
- ($what:expr, $where:expr) => {{
+ ($what:expr, $where:expr $(, $details:expr )?) => {{
let mut msg = format!("encountered {}", $what);
let where_ = &$where;
if !where_.is_empty() {
msg.push_str(" at ");
write_path(&mut msg, where_);
}
+ $( write!(&mut msg, ", but expected {}", $details).unwrap(); )?
throw_ub!(ValidationFailure(msg))
}};
}
+/// Returns a validation failure for any Err value of $e.
macro_rules! try_validation {
- ($e:expr, $what:expr, $where:expr, $details:expr) => {{
- match $e {
- Ok(x) => x,
- // We re-throw the error, so we are okay with allocation:
- // this can only slow down builds that fail anyway.
- Err(_) => throw_validation_failure!($what, $where, $details),
- }
+ ($e:expr, $what:expr, $where:expr $(, $details:expr )?) => {{
+ try_validation_pat!($e, _, $what, $where $(, $details )?)
}};
-
- ($e:expr, $what:expr, $where:expr) => {{
+}
+/// Like try_validation, but will throw a validation error if any of the patterns in $p are
+/// matched. Other errors are passed back to the caller, unchanged. This lets you use the patterns
+/// as a kind of validation blacklist:
+///
+/// ```rust
+/// let v = try_validation_pat(some_fn(), Foo | Bar | Baz, "some failure", "some place");
+/// // Failures that match $p are thrown up as validation errors, but other errors are passed back
+/// // unchanged.
+/// ```
+macro_rules! try_validation_pat {
+ ($e:expr, $( $p:pat )|*, $what:expr, $where:expr $(, $details:expr )?) => {{
match $e {
Ok(x) => x,
- // We re-throw the error, so we are okay with allocation:
- // this can only slow down builds that fail anyway.
- Err(_) => throw_validation_failure!($what, $where),
+ // We catch the error and turn it into a validation failure. We are okay with
+ // allocation here as this can only slow down builds that fail anyway.
+ $( Err($p) )|* if true => throw_validation_failure!($what, $where $(, $details)?),
+ Err(e) => Err::<!, _>(e)?,
}
}};
}
// Skip validation entirely for some external statics
let alloc_kind = self.ecx.tcx.alloc_map.lock().get(ptr.alloc_id);
if let Some(GlobalAlloc::Static(did)) = alloc_kind {
- // `extern static` cannot be validated as they have no body.
- // FIXME: Statics from other crates are also skipped.
- // They might be checked at a different type, but for now we
- // want to avoid recursing too deeply. This is not sound!
- if !did.is_local() || self.ecx.tcx.is_foreign_item(did) {
- return Ok(());
- }
+ // See const_eval::machine::MemoryExtra::can_access_statics for why
+ // this check is so important.
+ // This check is reachable when the const just referenced the static,
+ // but never read it (so we never entered `before_access_global`).
+ // We also need to do it here instead of going on to avoid running
+ // into the `before_access_global` check during validation.
if !self.may_ref_to_static && self.ecx.tcx.is_static(did) {
throw_validation_failure!(
format_args!("a {} pointing to a static variable", kind),
self.path
);
}
+ // `extern static` cannot be validated as they have no body.
+ // FIXME: Statics from other crates are also skipped.
+ // They might be checked at a different type, but for now we
+ // want to avoid recursing too deeply. We might miss const-invalid data,
+ // but things are still sound otherwise (in particular re: consts
+ // referring to statics).
+ if !did.is_local() || self.ecx.tcx.is_foreign_item(did) {
+ return Ok(());
+ }
}
}
// Proceed recursively even for ZST, no reason to skip them!
// We are conservative with undef for integers, but try to
// actually enforce the strict rules for raw pointers (mostly because
// that lets us re-use `ref_to_mplace`).
- let place = try_validation!(
+ let place = try_validation_pat!(
self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?),
+ _,
"uninitialized raw pointer",
self.path
);