Enforce that nobody can push/pop from the global environment stack

This is just a precaution.
This commit is contained in:
Peter Ammon
2024-06-19 12:50:02 -07:00
parent 7fcbe5b8ab
commit 9ad875cdb7
2 changed files with 22 additions and 2 deletions

View File

@@ -173,12 +173,14 @@ fn lock(&self) -> EnvMutexGuard<EnvScopedImpl> {
/// This backs the parser's "vars".
pub struct EnvStack {
inner: EnvMutex<EnvStackImpl>,
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<Event> {
pub fn globals() -> &'static EnvStack {
use std::sync::OnceLock;
static GLOBALS: OnceLock<EnvStack> = 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.

View File

@@ -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();
}