Fix deadlock in stdio.format calls in tostring metamethod (#288)

This commit is contained in:
dai 2025-03-24 19:34:51 +01:00 committed by GitHub
parent 822dd19393
commit dc08b91314
Signed by: DevComp
GPG key ID: B5690EEEBB952194
4 changed files with 27 additions and 7 deletions

1
Cargo.lock generated
View file

@ -1742,6 +1742,7 @@ dependencies = [
"dunce",
"mlua",
"once_cell",
"parking_lot",
"path-clean",
"pathdiff",
"semver 1.0.23",

View file

@ -22,4 +22,5 @@ dunce = "1.0"
once_cell = "1.17"
path-clean = "1.0"
pathdiff = "0.2"
parking_lot = "0.12.3"
semver = "1.0"

View file

@ -1,11 +1,9 @@
use std::{
collections::HashSet,
sync::{Arc, Mutex},
};
use std::{collections::HashSet, sync::Arc};
use console::{colors_enabled as get_colors_enabled, set_colors_enabled};
use mlua::prelude::*;
use once_cell::sync::Lazy;
use parking_lot::ReentrantMutex;
mod basic;
mod config;
@ -20,7 +18,7 @@ pub use self::config::ValueFormatConfig;
// NOTE: Since the setting for colors being enabled is global,
// and these functions may be called in parallel, we use this global
// lock to make sure that we don't mess up the colors for other threads.
static COLORS_LOCK: Lazy<Arc<Mutex<()>>> = Lazy::new(|| Arc::new(Mutex::new(())));
static COLORS_LOCK: Lazy<Arc<ReentrantMutex<()>>> = Lazy::new(|| Arc::new(ReentrantMutex::new(())));
/**
Formats a Lua value into a pretty string using the given config.
@ -28,7 +26,7 @@ static COLORS_LOCK: Lazy<Arc<Mutex<()>>> = Lazy::new(|| Arc::new(Mutex::new(()))
#[must_use]
#[allow(clippy::missing_panics_doc)]
pub fn pretty_format_value(value: &LuaValue, config: &ValueFormatConfig) -> String {
let _guard = COLORS_LOCK.lock().unwrap();
let _guard = COLORS_LOCK.lock();
let were_colors_enabled = get_colors_enabled();
set_colors_enabled(were_colors_enabled && config.colors_enabled);
@ -48,7 +46,7 @@ pub fn pretty_format_value(value: &LuaValue, config: &ValueFormatConfig) -> Stri
#[must_use]
#[allow(clippy::missing_panics_doc)]
pub fn pretty_format_multi_value(values: &LuaMultiValue, config: &ValueFormatConfig) -> String {
let _guard = COLORS_LOCK.lock().unwrap();
let _guard = COLORS_LOCK.lock();
let were_colors_enabled = get_colors_enabled();
set_colors_enabled(were_colors_enabled && config.colors_enabled);

View file

@ -122,3 +122,23 @@ stdio.ewrite(typeof(errorMessage))
assertContains("Should format errors similarly to userdata", stdio.format(errorMessage), "<LuaErr")
assertContains("Should format errors with stack begins", stdio.format(errorMessage), "Stack Begin")
assertContains("Should format errors with stack ends", stdio.format(errorMessage), "Stack End")
-- Check that calling stdio.format in a __tostring metamethod by print doesn't cause a deadlock
local inner = {}
setmetatable(inner, {
__tostring = function()
return stdio.format(5)
end,
})
print(inner)
local outer = {}
setmetatable(outer, {
__tostring = function()
return stdio.format(inner)
end,
})
print(outer)