diff --git a/src/ffi/internals51.rs b/src/ffi/internals51.rs new file mode 100644 index 0000000..24751e2 --- /dev/null +++ b/src/ffi/internals51.rs @@ -0,0 +1,120 @@ +// The MIT License (MIT) +// +// Copyright (c) 2020 A. Orlenko +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +use std::os::raw::*; + +use crate::ffi::{lua_Alloc, lua_CFunction, lua_Hook, lua_Number, lua_State}; + +#[repr(C)] +struct lua_StateExt { + next: *mut c_void, + tt: u8, + marked: u8, + status: u8, + top: *mut c_void, + base: *mut c_void, + l_G: *mut global_State, + ci: *mut c_void, + savedpc: *const c_void, + stack_last: *mut c_void, + stack: *mut c_void, + end_ci: *mut c_void, + base_ci: *mut c_void, + stacksize: c_int, + size_ci: c_int, + nCcalls: c_ushort, + baseCcalls: c_ushort, + hookmask: u8, + allowhook: u8, + basehookcount: c_int, + hookcount: c_int, + hook: Option, + l_gt: TValue, + env: TValue, + openupval: *mut c_void, + gclist: *mut c_void, + errorJmp: *mut c_void, + errfunc: isize, +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct TValue { + value: Value, + tt: c_int, +} + +#[repr(C)] +#[derive(Clone, Copy)] +union Value { + gc: *mut c_void, + p: *mut c_void, + n: lua_Number, + b: c_int, +} + +#[repr(C)] +struct global_State { + strt: stringtable, + frealloc: Option, + ud: *mut c_void, + currentwhite: u8, + gcstate: u8, + sweepstrgc: c_int, + rootgc: *mut c_void, + sweepgc: *mut c_void, + gray: *mut c_void, + grayagain: *mut c_void, + weak: *mut c_void, + tmudata: *mut c_void, + buff: Mbuffer, + GCthreshold: usize, + totalbytes: usize, + estimate: usize, + gcdept: usize, + gcpause: c_int, + gcstepmul: c_int, + panic: Option, + l_registry: TValue, + mainthread: *mut lua_State, + // Other fields ommited +} + +#[repr(C)] +struct stringtable { + hash: *mut c_void, + nuse: c_uint, + size: c_int, +} + +#[repr(C)] +struct Mbuffer { + buffer: *mut c_char, + n: usize, + buffsize: usize, +} + +pub unsafe fn lua_getmainstate(state: *mut lua_State) -> *mut lua_State { + let state = state as *mut lua_StateExt; + let global = (*state).l_G; + (*global).mainthread +} diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 78059a2..cab2f09 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -170,6 +170,9 @@ pub use self::lua::{lua_isyieldable, lua_version}; #[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))] pub use self::lua::{lua_callk, lua_pcallk, lua_upvalueid, lua_upvaluejoin, lua_yieldk}; +#[cfg(feature = "lua51")] +pub use self::internals51::lua_getmainstate; + // auxiliary library types pub use self::lauxlib::luaL_Reg; @@ -284,6 +287,9 @@ mod glue { #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] mod compat53; +#[cfg(feature = "lua51")] +mod internals51; + mod lauxlib; mod lua; mod luaconf; diff --git a/src/lua.rs b/src/lua.rs index e13dcb5..b444384 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -279,7 +279,7 @@ impl Lua { #[allow(clippy::missing_safety_doc)] pub unsafe fn init_from_ptr(state: *mut ffi::lua_State) -> Lua { let main_state = get_main_state(state); - let main_state_top = ffi::lua_gettop(state); + let main_state_top = ffi::lua_gettop(main_state); let ref_thread = mlua_expect!( protect_lua_closure(main_state, 0, 0, |state| { @@ -324,7 +324,7 @@ impl Lua { })); mlua_expect!( - push_gc_userdata(state, Arc::downgrade(&extra)), + push_gc_userdata(main_state, Arc::downgrade(&extra)), "Error while storing extra data", ); mlua_expect!( diff --git a/src/util.rs b/src/util.rs index eba93e9..d729155 100644 --- a/src/util.rs +++ b/src/util.rs @@ -493,7 +493,19 @@ pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> *mut ffi::lua_State ffi::lua_pop(state, 1); main_state } - #[cfg(any(feature = "lua51", feature = "luajit"))] + #[cfg(feature = "lua51")] + { + // Check the current state first + let is_main_state = ffi::lua_pushthread(state) == 1; + ffi::lua_pop(state, 1); + if is_main_state { + state + } else { + // The function below is a dirty hack and uses Lua private internals + ffi::lua_getmainstate(state) + } + } + #[cfg(feature = "luajit")] state }