Skip to content

Commit d7d87bd

Browse files
authored
Merge branch 'mlua-rs:main' into main
2 parents 09dfc9b + cd4091f commit d7d87bd

19 files changed

+160
-62
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## v0.10.2 (Dec 1st, 2024)
2+
3+
- Switch proc-macro-error to proc-macro-error2 (#493)
4+
- Do not allow Lua to run GC finalizers on ref thread (#491)
5+
- Fix chunks loading in Luau when memory limit is enforced (#488)
6+
- Added `String::wrap` method to wrap arbitrary `AsRef<[u8]>` into `impl IntoLua`
7+
- Better FreeBSD/OpenBSD support (thanks to cos)
8+
- Delay "any" userdata metatable creation until first instance is created (#482)
9+
- Reduce amount of generated code for `UserData` (less generics)
10+
111
## v0.10.1 (Nov 9th, 2024)
212

313
- Minimal Luau updated to 0.650

Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mlua"
3-
version = "0.10.1" # remember to update mlua_derive
3+
version = "0.10.2" # remember to update mlua_derive
44
authors = ["Aleksandr Orlenko <[email protected]>", "kyren <[email protected]>"]
55
rust-version = "1.79.0"
66
edition = "2021"
@@ -46,7 +46,7 @@ anyhow = ["dep:anyhow", "error-send"]
4646
userdata-wrappers = []
4747

4848
[dependencies]
49-
mlua_derive = { version = "=0.10.0", optional = true, path = "mlua_derive" }
49+
mlua_derive = { version = "=0.10.1", optional = true, path = "mlua_derive" }
5050
bstr = { version = "1.0", features = ["std"], default-features = false }
5151
either = "1.0"
5252
num-traits = { version = "0.2.14" }
@@ -58,7 +58,7 @@ serde-value = { version = "0.7", optional = true }
5858
parking_lot = { version = "0.12", features = ["arc_lock"] }
5959
anyhow = { version = "1.0", optional = true }
6060

61-
ffi = { package = "mlua-sys", version = "0.6.5", path = "mlua-sys" }
61+
ffi = { package = "mlua-sys", version = "0.6.6", path = "mlua-sys" }
6262

6363
[target.'cfg(unix)'.dependencies]
6464
libloading = { version = "0.8", optional = true }

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ Add to `Cargo.toml` :
133133

134134
``` toml
135135
[dependencies]
136-
mlua = { version = "0.10.1", features = ["lua54", "vendored"] }
136+
mlua = { version = "0.10.2", features = ["lua54", "vendored"] }
137137
```
138138

139139
`main.rs`
@@ -168,7 +168,7 @@ Add to `Cargo.toml` :
168168
crate-type = ["cdylib"]
169169

170170
[dependencies]
171-
mlua = { version = "0.10.1", features = ["lua54", "module"] }
171+
mlua = { version = "0.10.2", features = ["lua54", "module"] }
172172
```
173173

174174
`lib.rs` :

mlua-sys/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mlua-sys"
3-
version = "0.6.5"
3+
version = "0.6.6"
44
authors = ["Aleksandr Orlenko <[email protected]>"]
55
rust-version = "1.71"
66
edition = "2021"

mlua-sys/src/luau/compat.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,16 @@ pub unsafe fn luaL_loadbufferenv(
326326
mut size: usize,
327327
name: *const c_char,
328328
mode: *const c_char,
329-
env: c_int,
329+
mut env: c_int,
330330
) -> c_int {
331331
extern "C" {
332332
fn free(p: *mut c_void);
333333
}
334334

335+
unsafe extern "C-unwind" fn data_dtor(data: *mut c_void) {
336+
free(*(data as *mut *mut c_char) as *mut c_void);
337+
}
338+
335339
let chunk_is_text = size == 0 || (*data as u8) >= b'\t';
336340
if !mode.is_null() {
337341
let modeb = CStr::from_ptr(mode).to_bytes();
@@ -345,9 +349,16 @@ pub unsafe fn luaL_loadbufferenv(
345349
}
346350

347351
if chunk_is_text {
352+
if env < 0 {
353+
env -= 1;
354+
}
355+
let data_ud = lua_newuserdatadtor(L, mem::size_of::<*mut c_char>(), data_dtor) as *mut *mut c_char;
348356
let data = luau_compile_(data, size, ptr::null_mut(), &mut size);
357+
ptr::write(data_ud, data);
358+
// By deferring the `free(data)` to the userdata destructor, we ensure that
359+
// even if `luau_load` throws an error, the `data` is still released.
349360
let ok = luau_load(L, name, data, size, env) == 0;
350-
free(data as *mut c_void);
361+
lua_replace(L, -2); // replace data with the result
351362
if !ok {
352363
return LUA_ERRSYNTAX;
353364
}

mlua_derive/Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mlua_derive"
3-
version = "0.10.0"
3+
version = "0.10.1"
44
authors = ["Aleksandr Orlenko <[email protected]>"]
55
edition = "2021"
66
description = "Procedural macros for the mlua crate."
@@ -12,12 +12,12 @@ license = "MIT"
1212
proc-macro = true
1313

1414
[features]
15-
macros = ["proc-macro-error", "itertools", "regex", "once_cell"]
15+
macros = ["proc-macro-error2", "itertools", "regex", "once_cell"]
1616

1717
[dependencies]
1818
quote = "1.0"
1919
proc-macro2 = { version = "1.0", features = ["span-locations"] }
20-
proc-macro-error = { version = "1.0", optional = true }
20+
proc-macro-error2 = { version = "2.0.1", optional = true }
2121
syn = { version = "2.0", features = ["full"] }
2222
itertools = { version = "0.13", optional = true }
2323
regex = { version = "1.4", optional = true }

mlua_derive/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use syn::{parse_macro_input, ItemFn, LitStr, Result};
77
#[cfg(feature = "macros")]
88
use {
99
crate::chunk::Chunk, proc_macro::TokenTree, proc_macro2::TokenStream as TokenStream2,
10-
proc_macro_error::proc_macro_error,
10+
proc_macro_error2::proc_macro_error,
1111
};
1212

1313
#[derive(Default)]

mlua_derive/src/token.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ fn parse_pos(span: &Span) -> Option<(usize, usize)> {
7474
fn fallback_span_pos(span: &Span) -> (Pos, Pos) {
7575
let (start, end) = match parse_pos(span) {
7676
Some(v) => v,
77-
None => proc_macro_error::abort_call_site!("Cannot retrieve span information; please use nightly"),
77+
None => proc_macro_error2::abort_call_site!("Cannot retrieve span information; please use nightly"),
7878
};
7979
(Pos::new(1, start), Pos::new(1, end))
8080
}

src/state.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1043,8 +1043,8 @@ impl Lua {
10431043
let state = lua.state();
10441044
unsafe {
10451045
if lua.unlikely_memory_error() {
1046-
crate::util::push_buffer(lua.ref_thread(), buf.as_ref(), false)?;
1047-
return Ok(Buffer(lua.pop_ref_thread()));
1046+
crate::util::push_buffer(state, buf.as_ref(), false)?;
1047+
return Ok(Buffer(lua.pop_ref()));
10481048
}
10491049

10501050
let _sg = StackGuard::new(state);

src/state/extra.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use super::{Lua, WeakLua};
2727
// Unique key to store `ExtraData` in the registry
2828
static EXTRA_REGISTRY_KEY: u8 = 0;
2929

30-
const WRAPPED_FAILURE_POOL_SIZE: usize = 64;
30+
const WRAPPED_FAILURE_POOL_DEFAULT_CAPACITY: usize = 64;
3131
const REF_STACK_RESERVE: c_int = 1;
3232

3333
/// Data associated with the Lua state.
@@ -60,6 +60,7 @@ pub(crate) struct ExtraData {
6060

6161
// Pool of `WrappedFailure` enums in the ref thread (as userdata)
6262
pub(super) wrapped_failure_pool: Vec<c_int>,
63+
pub(super) wrapped_failure_top: usize,
6364
// Pool of `Thread`s (coroutines) for async execution
6465
#[cfg(feature = "async")]
6566
pub(super) thread_pool: Vec<c_int>,
@@ -160,7 +161,8 @@ impl ExtraData {
160161
ref_stack_size: ffi::LUA_MINSTACK - REF_STACK_RESERVE,
161162
ref_stack_top: ffi::lua_gettop(ref_thread),
162163
ref_free: Vec::new(),
163-
wrapped_failure_pool: Vec::with_capacity(WRAPPED_FAILURE_POOL_SIZE),
164+
wrapped_failure_pool: Vec::with_capacity(WRAPPED_FAILURE_POOL_DEFAULT_CAPACITY),
165+
wrapped_failure_top: 0,
164166
#[cfg(feature = "async")]
165167
thread_pool: Vec::new(),
166168
wrapped_failure_mt_ptr,

src/state/raw.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -327,10 +327,10 @@ impl RawLua {
327327
Some(ChunkMode::Text) => cstr!("t"),
328328
None => cstr!("bt"),
329329
};
330-
let status = if cfg!(not(feature = "luau")) || self.unlikely_memory_error() {
330+
let status = if self.unlikely_memory_error() {
331331
self.load_chunk_inner(state, name, env, mode, source)
332332
} else {
333-
// Only Luau can trigger an exception during chunk loading
333+
// Luau and Lua 5.2 can trigger an exception during chunk loading
334334
protect_lua!(state, 0, 1, |state| {
335335
self.load_chunk_inner(state, name, env, mode, source)
336336
})?
@@ -427,8 +427,8 @@ impl RawLua {
427427
pub(crate) unsafe fn create_string(&self, s: impl AsRef<[u8]>) -> Result<String> {
428428
let state = self.state();
429429
if self.unlikely_memory_error() {
430-
push_string(self.ref_thread(), s.as_ref(), false)?;
431-
return Ok(String(self.pop_ref_thread()));
430+
push_string(state, s.as_ref(), false)?;
431+
return Ok(String(self.pop_ref()));
432432
}
433433

434434
let _sg = StackGuard::new(state);
@@ -439,12 +439,12 @@ impl RawLua {
439439

440440
/// See [`Lua::create_table_with_capacity`]
441441
pub(crate) unsafe fn create_table_with_capacity(&self, narr: usize, nrec: usize) -> Result<Table> {
442+
let state = self.state();
442443
if self.unlikely_memory_error() {
443-
push_table(self.ref_thread(), narr, nrec, false)?;
444-
return Ok(Table(self.pop_ref_thread()));
444+
push_table(state, narr, nrec, false)?;
445+
return Ok(Table(self.pop_ref()));
445446
}
446447

447-
let state = self.state();
448448
let _sg = StackGuard::new(state);
449449
check_stack(state, 3)?;
450450
push_table(state, narr, nrec, true)?;
@@ -729,6 +729,10 @@ impl RawLua {
729729

730730
pub(crate) unsafe fn drop_ref(&self, vref: &ValueRef) {
731731
let ref_thread = self.ref_thread();
732+
mlua_debug_assert!(
733+
ffi::lua_gettop(ref_thread) >= vref.index,
734+
"GC finalizer is not allowed in ref_thread"
735+
);
732736
ffi::lua_pushnil(ref_thread);
733737
ffi::lua_replace(ref_thread, vref.index);
734738
(*self.extra.get()).ref_free.push(vref.index);

src/state/util.rs

+23-35
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ use crate::error::{Error, Result};
77
use crate::state::{ExtraData, RawLua};
88
use crate::util::{self, get_internal_metatable, WrappedFailure};
99

10-
const WRAPPED_FAILURE_POOL_SIZE: usize = 64;
11-
1210
pub(super) struct StateGuard<'a>(&'a RawLua, *mut ffi::lua_State);
1311

1412
impl<'a> StateGuard<'a> {
@@ -42,39 +40,40 @@ where
4240

4341
enum PreallocatedFailure {
4442
New(*mut WrappedFailure),
45-
Existing(i32),
43+
Reserved,
4644
}
4745

4846
impl PreallocatedFailure {
4947
unsafe fn reserve(state: *mut ffi::lua_State, extra: *mut ExtraData) -> Self {
50-
match (*extra).wrapped_failure_pool.pop() {
51-
Some(index) => PreallocatedFailure::Existing(index),
52-
None => {
53-
// We need to check stack for Luau in case when callback is called from interrupt
54-
// See https://github.com/Roblox/luau/issues/446 and mlua #142 and #153
55-
#[cfg(feature = "luau")]
56-
ffi::lua_rawcheckstack(state, 2);
57-
// Place it to the beginning of the stack
58-
let ud = WrappedFailure::new_userdata(state);
59-
ffi::lua_insert(state, 1);
60-
PreallocatedFailure::New(ud)
61-
}
48+
if (*extra).wrapped_failure_top > 0 {
49+
(*extra).wrapped_failure_top -= 1;
50+
return PreallocatedFailure::Reserved;
6251
}
52+
53+
// We need to check stack for Luau in case when callback is called from interrupt
54+
// See https://github.com/Roblox/luau/issues/446 and mlua #142 and #153
55+
#[cfg(feature = "luau")]
56+
ffi::lua_rawcheckstack(state, 2);
57+
// Place it to the beginning of the stack
58+
let ud = WrappedFailure::new_userdata(state);
59+
ffi::lua_insert(state, 1);
60+
PreallocatedFailure::New(ud)
6361
}
6462

63+
#[cold]
6564
unsafe fn r#use(&self, state: *mut ffi::lua_State, extra: *mut ExtraData) -> *mut WrappedFailure {
6665
let ref_thread = (*extra).ref_thread;
6766
match *self {
6867
PreallocatedFailure::New(ud) => {
6968
ffi::lua_settop(state, 1);
7069
ud
7170
}
72-
PreallocatedFailure::Existing(index) => {
71+
PreallocatedFailure::Reserved => {
72+
let index = (*extra).wrapped_failure_pool.pop().unwrap();
7373
ffi::lua_settop(state, 0);
7474
#[cfg(feature = "luau")]
7575
ffi::lua_rawcheckstack(state, 2);
76-
ffi::lua_pushvalue(ref_thread, index);
77-
ffi::lua_xmove(ref_thread, state, 1);
76+
ffi::lua_xpush(ref_thread, state, index);
7877
ffi::lua_pushnil(ref_thread);
7978
ffi::lua_replace(ref_thread, index);
8079
(*extra).ref_free.push(index);
@@ -87,24 +86,13 @@ where
8786
let ref_thread = (*extra).ref_thread;
8887
match self {
8988
PreallocatedFailure::New(_) => {
90-
if (*extra).wrapped_failure_pool.len() < WRAPPED_FAILURE_POOL_SIZE {
91-
ffi::lua_rotate(state, 1, -1);
92-
ffi::lua_xmove(state, ref_thread, 1);
93-
let index = ref_stack_pop(extra);
94-
(*extra).wrapped_failure_pool.push(index);
95-
} else {
96-
ffi::lua_remove(state, 1);
97-
}
98-
}
99-
PreallocatedFailure::Existing(index) => {
100-
if (*extra).wrapped_failure_pool.len() < WRAPPED_FAILURE_POOL_SIZE {
101-
(*extra).wrapped_failure_pool.push(index);
102-
} else {
103-
ffi::lua_pushnil(ref_thread);
104-
ffi::lua_replace(ref_thread, index);
105-
(*extra).ref_free.push(index);
106-
}
89+
ffi::lua_rotate(state, 1, -1);
90+
ffi::lua_xmove(state, ref_thread, 1);
91+
let index = ref_stack_pop(extra);
92+
(*extra).wrapped_failure_pool.push(index);
93+
(*extra).wrapped_failure_top += 1;
10794
}
95+
PreallocatedFailure::Reserved => (*extra).wrapped_failure_top += 1,
10896
}
10997
}
11098
}

src/table.rs

+18
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,24 @@ impl Table {
581581
unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
582582
}
583583

584+
/// Controls `safeenv` attribute on the table.
585+
///
586+
/// This a special flag that activates some performance optimizations for environment tables.
587+
/// In particular, it controls:
588+
/// - Optimization of import resolution (cache values of constant keys).
589+
/// - Fast-path for built-in iteration with pairs/ipairs.
590+
/// - Fast-path for some built-in functions (fastcall).
591+
///
592+
/// For `safeenv` environments, monkey patching or modifying values may not work as expected.
593+
///
594+
/// Requires `feature = "luau"`
595+
#[cfg(any(feature = "luau", doc))]
596+
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
597+
pub fn set_safeenv(&self, enabled: bool) {
598+
let lua = self.0.lua.lock();
599+
unsafe { ffi::lua_setsafeenv(lua.ref_thread(), self.0.index, enabled as _) };
600+
}
601+
584602
/// Converts this table to a generic C pointer.
585603
///
586604
/// Different tables will give different pointers.

src/types/value_ref.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::os::raw::{c_int, c_void};
44
use crate::state::{RawLua, WeakLua};
55

66
/// A reference to a Lua (complex) value stored in the Lua auxiliary thread.
7-
pub(crate) struct ValueRef {
7+
pub struct ValueRef {
88
pub(crate) lua: WeakLua,
99
pub(crate) index: c_int,
1010
pub(crate) drop: bool,

src/value.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ pub enum Value {
6767
/// `Error` is a special builtin userdata type. When received from Lua it is implicitly cloned.
6868
Error(Box<Error>),
6969
/// Any other value not known to mlua (eg. LuaJIT CData).
70-
#[allow(private_interfaces)]
71-
Other(ValueRef),
70+
Other(#[doc(hidden)] ValueRef),
7271
}
7372

7473
pub use self::Value::Nil;

tests/hooks.rs

+12
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,21 @@ fn test_function_calls() -> Result<()> {
7575

7676
let output = output.lock().unwrap();
7777
if cfg!(feature = "luajit") && lua.load("jit.version_num").eval::<i64>()? >= 20100 {
78+
#[cfg(not(force_memory_limit))]
7879
assert_eq!(*output, vec![(None, "main"), (Some("len".to_string()), "Lua")]);
80+
#[cfg(force_memory_limit)]
81+
assert_eq!(
82+
*output,
83+
vec![(None, "C"), (None, "main"), (Some("len".to_string()), "Lua")]
84+
);
7985
} else {
86+
#[cfg(not(force_memory_limit))]
8087
assert_eq!(*output, vec![(None, "main"), (Some("len".to_string()), "C")]);
88+
#[cfg(force_memory_limit)]
89+
assert_eq!(
90+
*output,
91+
vec![(None, "C"), (None, "main"), (Some("len".to_string()), "C")]
92+
);
8193
}
8294

8395
Ok(())

0 commit comments

Comments
 (0)