diff --git a/src/env/environment.rs b/src/env/environment.rs index 8348b3504..5baa27edf 100644 --- a/src/env/environment.rs +++ b/src/env/environment.rs @@ -173,12 +173,14 @@ fn lock(&self) -> EnvMutexGuard { /// This backs the parser's "vars". pub struct EnvStack { inner: EnvMutex, + can_push_pop: bool, // If false, panic on push/pop. Used for the global stack. } impl EnvStack { pub fn new() -> EnvStack { EnvStack { inner: EnvStackImpl::new(), + can_push_pop: true, } } @@ -291,6 +293,7 @@ pub fn remove(&self, key: &wstr, mode: EnvMode) -> EnvStackSetResult { /// Push the variable stack. Used for implementing local variables for functions and for-loops. pub fn push(&self, new_scope: bool) { + assert!(self.can_push_pop, "push/pop not allowed on global stack"); let mut imp = self.lock(); if new_scope { imp.push_shadowing(); @@ -301,6 +304,7 @@ pub fn push(&self, new_scope: bool) { /// Pop the variable stack. Used for implementing local variables for functions and for-loops. pub fn pop(&self) { + assert!(self.can_push_pop, "push/pop not allowed on global stack"); let popped = self.lock().pop(); // Only dispatch variable changes if we are the principal environment. if self.is_principal() { @@ -363,7 +367,10 @@ pub fn universal_sync(&self, always: bool) -> Vec { pub fn globals() -> &'static EnvStack { use std::sync::OnceLock; static GLOBALS: OnceLock = OnceLock::new(); - GLOBALS.get_or_init(EnvStack::new) + GLOBALS.get_or_init(|| EnvStack { + inner: EnvStackImpl::new(), + can_push_pop: false, + }) } /// Access the principal variable stack, associated with the principal parser. diff --git a/src/tests/env.rs b/src/tests/env.rs index 106c497dc..a90de33d2 100644 --- a/src/tests/env.rs +++ b/src/tests/env.rs @@ -1,4 +1,4 @@ -use crate::env::{EnvMode, EnvVar, EnvVarFlags, Environment}; +use crate::env::{EnvMode, EnvStack, EnvVar, EnvVarFlags, Environment}; use crate::parser::Parser; use crate::tests::prelude::*; use crate::wchar::prelude::*; @@ -177,3 +177,16 @@ fn test_env_snapshot() { vars.pop(); popd(); } + +// Can't push/pop from globals. +#[test] +#[should_panic] +fn test_no_global_push() { + EnvStack::globals().push(true); +} + +#[test] +#[should_panic] +fn test_no_global_pop() { + EnvStack::globals().pop(); +}