about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhyd-dev <yd-huang@outlook.com>2021-05-25 00:08:26 +0800
committerhyd-dev <yd-huang@outlook.com>2021-05-25 03:42:25 +0800
commit64044eb2371d955c2e854f849eaccb45dbd33c4a (patch)
tree408f6b6103ec5a0debe272213e3c315b3a1a43f2
parentac39f365266fcbfaf8d1fb31ac59feba60950e92 (diff)
downloadrust-64044eb2371d955c2e854f849eaccb45dbd33c4a.tar.gz
rust-64044eb2371d955c2e854f849eaccb45dbd33c4a.zip
Check whether unwinding is allowed before popping the stack frame
-rw-r--r--compiler/rustc_mir/src/interpret/eval_context.rs31
1 files changed, 15 insertions, 16 deletions
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index f1ba669492f..bb894e5ce0b 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -798,26 +798,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             throw_ub_format!("unwinding past the topmost frame of the stack");
         }
 
-        let frame =
-            self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
-
-        if !unwinding {
-            // Copy the return value to the caller's stack frame.
-            if let Some(ref return_place) = frame.return_place {
-                let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
-                self.copy_op_transmute(&op, return_place)?;
-                trace!("{:?}", self.dump_place(**return_place));
-            } else {
-                throw_ub!(Unreachable);
-            }
-        }
-
-        // Now where do we jump next?
+        // Where do we jump next?
 
         // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
         // In that case, we return early. We also avoid validation in that case,
         // because this is CTFE and the final value will be thoroughly validated anyway.
-        let (cleanup, next_block) = match (frame.return_to_block, unwinding) {
+        let (cleanup, next_block) = match (self.frame().return_to_block, unwinding) {
             (StackPopCleanup::Goto { ret, .. }, false) => (true, Some(ret)),
             (StackPopCleanup::Goto { unwind, .. }, true) => (
                 true,
@@ -832,6 +818,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             (StackPopCleanup::None { cleanup, .. }, _) => (cleanup, None),
         };
 
+        let frame = self.stack_mut().pop().unwrap();
+
+        if !unwinding {
+            // Copy the return value to the caller's stack frame.
+            if let Some(ref return_place) = frame.return_place {
+                let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
+                self.copy_op_transmute(&op, return_place)?;
+                trace!("{:?}", self.dump_place(**return_place));
+            } else {
+                throw_ub!(Unreachable);
+            }
+        }
+
         if !cleanup {
             assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
             assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!");