From eddd07cc8a92dd603e9884789fb58b2d3edd2e16 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 22 Feb 2019 13:36:04 +1100 Subject: [PATCH] Make `visit_clobber` panic-safe. --- src/libsyntax/mut_visit.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 1e5eb0992bd1b..b7d22b3d554f3 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -21,6 +21,7 @@ use syntax_pos::Span; use rustc_data_structures::sync::Lrc; use std::ops::DerefMut; +use std::{panic, process, ptr}; pub trait ExpectOne { fn expect_one(self, err: &'static str) -> A::Item; @@ -305,11 +306,18 @@ pub trait MutVisitor: Sized { /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful /// when using a `flat_map_*` or `filter_map_*` method within a `visit_` -/// method. +/// method. Abort the program if the closure panics. // // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. pub fn visit_clobber(t: &mut T, f: F) where F: FnOnce(T) -> T { - unsafe { std::ptr::write(t, f(std::ptr::read(t))); } + unsafe { + // Safe because `t` is used in a read-only fashion by `read()` before + // being overwritten by `write()`. + let old_t = ptr::read(t); + let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t))) + .unwrap_or_else(|_| process::abort()); + ptr::write(t, new_t); + } } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.