Skip to content

Commit dc08b91

Browse files
author
dai
authored
Fix deadlock in stdio.format calls in tostring metamethod (lune-org#288)
1 parent 822dd19 commit dc08b91

File tree

4 files changed

+27
-7
lines changed

4 files changed

+27
-7
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/lune-utils/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ dunce = "1.0"
2222
once_cell = "1.17"
2323
path-clean = "1.0"
2424
pathdiff = "0.2"
25+
parking_lot = "0.12.3"
2526
semver = "1.0"

crates/lune-utils/src/fmt/value/mod.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
use std::{
2-
collections::HashSet,
3-
sync::{Arc, Mutex},
4-
};
1+
use std::{collections::HashSet, sync::Arc};
52

63
use console::{colors_enabled as get_colors_enabled, set_colors_enabled};
74
use mlua::prelude::*;
85
use once_cell::sync::Lazy;
6+
use parking_lot::ReentrantMutex;
97

108
mod basic;
119
mod config;
@@ -20,15 +18,15 @@ pub use self::config::ValueFormatConfig;
2018
// NOTE: Since the setting for colors being enabled is global,
2119
// and these functions may be called in parallel, we use this global
2220
// lock to make sure that we don't mess up the colors for other threads.
23-
static COLORS_LOCK: Lazy<Arc<Mutex<()>>> = Lazy::new(|| Arc::new(Mutex::new(())));
21+
static COLORS_LOCK: Lazy<Arc<ReentrantMutex<()>>> = Lazy::new(|| Arc::new(ReentrantMutex::new(())));
2422

2523
/**
2624
Formats a Lua value into a pretty string using the given config.
2725
*/
2826
#[must_use]
2927
#[allow(clippy::missing_panics_doc)]
3028
pub fn pretty_format_value(value: &LuaValue, config: &ValueFormatConfig) -> String {
31-
let _guard = COLORS_LOCK.lock().unwrap();
29+
let _guard = COLORS_LOCK.lock();
3230

3331
let were_colors_enabled = get_colors_enabled();
3432
set_colors_enabled(were_colors_enabled && config.colors_enabled);
@@ -48,7 +46,7 @@ pub fn pretty_format_value(value: &LuaValue, config: &ValueFormatConfig) -> Stri
4846
#[must_use]
4947
#[allow(clippy::missing_panics_doc)]
5048
pub fn pretty_format_multi_value(values: &LuaMultiValue, config: &ValueFormatConfig) -> String {
51-
let _guard = COLORS_LOCK.lock().unwrap();
49+
let _guard = COLORS_LOCK.lock();
5250

5351
let were_colors_enabled = get_colors_enabled();
5452
set_colors_enabled(were_colors_enabled && config.colors_enabled);

tests/stdio/format.luau

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,23 @@ stdio.ewrite(typeof(errorMessage))
122122
assertContains("Should format errors similarly to userdata", stdio.format(errorMessage), "<LuaErr")
123123
assertContains("Should format errors with stack begins", stdio.format(errorMessage), "Stack Begin")
124124
assertContains("Should format errors with stack ends", stdio.format(errorMessage), "Stack End")
125+
126+
-- Check that calling stdio.format in a __tostring metamethod by print doesn't cause a deadlock
127+
128+
local inner = {}
129+
setmetatable(inner, {
130+
__tostring = function()
131+
return stdio.format(5)
132+
end,
133+
})
134+
135+
print(inner)
136+
137+
local outer = {}
138+
setmetatable(outer, {
139+
__tostring = function()
140+
return stdio.format(inner)
141+
end,
142+
})
143+
144+
print(outer)

0 commit comments

Comments
 (0)