Skip to content

Commit 651e830

Browse files
authored
Merge pull request #236 from amethyst/load_loadfile_issue116_rb
Fix #116: * Add wrappers for load/loadfile etc. which forbid loading compiled Lua chunks by default. * Add Function::dump() to get the compiled Lua chunks and unsafe function to loadit. * Add InitFlags for allowing `package.loadlib` or the unrestricted `load`/`loadfile`/`dofile`.
2 parents 64ffa90 + 1a56538 commit 651e830

File tree

8 files changed

+801
-37
lines changed

8 files changed

+801
-37
lines changed

.circleci/config.yml

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ jobs:
2020
- restore_cache:
2121
keys:
2222
- cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}
23-
- run:
24-
name: Check Formatting
25-
command: |
26-
rustup component add rustfmt
27-
rustfmt --version
28-
cargo fmt --all -- --check --color=auto
2923
- run:
3024
name: Build all targets
3125
command: cargo build --all --all-targets
3226
- run:
3327
name: Run all tests
3428
command: cargo test --all
29+
- run:
30+
name: Check Formatting
31+
command: |
32+
rustup component add rustfmt
33+
rustfmt --version
34+
cargo fmt --all -- --check --color=auto
3535
- save_cache:
3636
paths:
3737
- /usr/local/cargo/registry
@@ -58,18 +58,18 @@ jobs:
5858
- restore_cache:
5959
keys:
6060
- cargo-cache-lua53-{{ arch }}-{{ checksum "Cargo.lock" }}
61-
- run:
62-
name: Check Formatting
63-
command: |
64-
rustup component add rustfmt
65-
rustfmt --version
66-
cargo fmt --all -- --check --color=auto
6761
- run:
6862
name: Build all targets
6963
command: cargo build --no-default-features --features=builtin-lua53 --all --all-targets
7064
- run:
7165
name: Run all tests
7266
command: cargo test --no-default-features --features=builtin-lua53 --all
67+
- run:
68+
name: Check Formatting
69+
command: |
70+
rustup component add rustfmt
71+
rustfmt --version
72+
cargo fmt --all -- --check --color=auto
7373
- save_cache:
7474
paths:
7575
- /usr/local/cargo/registry
@@ -102,18 +102,18 @@ jobs:
102102
- restore_cache:
103103
keys:
104104
- cargo-cache-lua51-{{ arch }}-{{ checksum "Cargo.lock" }}
105-
- run:
106-
name: Check Formatting
107-
command: |
108-
rustup component add rustfmt
109-
rustfmt --version
110-
cargo fmt --all -- --check --color=auto
111105
- run:
112106
name: Build all targets
113107
command: cargo build --no-default-features --features=system-lua51 --all --all-targets
114108
- run:
115109
name: Run all tests
116110
command: cargo test --no-default-features --features=system-lua51 --all
111+
- run:
112+
name: Check Formatting
113+
command: |
114+
rustup component add rustfmt
115+
rustfmt --version
116+
cargo fmt --all -- --check --color=auto
117117
- save_cache:
118118
paths:
119119
- /usr/local/cargo/registry

crates/rlua-lua51-sys/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub use {
6868

6969
pub use {
7070
bindings::lua_Alloc, bindings::lua_CFunction, bindings::lua_Debug, bindings::lua_Integer,
71-
bindings::lua_Number, bindings::lua_State,
71+
bindings::lua_Number, bindings::lua_State, bindings::lua_Writer,
7272
};
7373

7474
/*
@@ -143,8 +143,8 @@ pub use bindings::lua_gc;
143143
** miscellaneous functions
144144
*/
145145
pub use {
146-
bindings::lua_concat, bindings::lua_error, bindings::lua_getallocf, bindings::lua_next,
147-
bindings::lua_setallocf,
146+
bindings::lua_concat, bindings::lua_dump, bindings::lua_error, bindings::lua_getallocf,
147+
bindings::lua_next, bindings::lua_setallocf,
148148
};
149149

150150
/*

src/context.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -856,26 +856,32 @@ impl<'lua> Context<'lua> {
856856
source: &[u8],
857857
name: Option<&CString>,
858858
env: Option<Value<'lua>>,
859+
allow_binary: bool,
859860
) -> Result<Function<'lua>> {
860861
unsafe {
861862
let _sg = StackGuard::new(self.state);
862863
assert_stack(self.state, 1);
864+
let mode = if allow_binary {
865+
cstr!("bt")
866+
} else {
867+
cstr!("t")
868+
};
863869

864870
match if let Some(name) = name {
865871
loadbufferx(
866872
self.state,
867873
source.as_ptr() as *const c_char,
868874
source.len(),
869875
name.as_ptr() as *const c_char,
870-
cstr!("t"),
876+
mode,
871877
)
872878
} else {
873879
loadbufferx(
874880
self.state,
875881
source.as_ptr() as *const c_char,
876882
source.len(),
877883
ptr::null(),
878-
cstr!("t"),
884+
mode,
879885
)
880886
} {
881887
ffi::LUA_OK => {
@@ -956,10 +962,12 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
956962
// actual lua repl does.
957963
let mut expression_source = b"return ".to_vec();
958964
expression_source.extend(self.source);
959-
if let Ok(function) =
960-
self.context
961-
.load_chunk(&expression_source, self.name.as_ref(), self.env.clone())
962-
{
965+
if let Ok(function) = self.context.load_chunk(
966+
&expression_source,
967+
self.name.as_ref(),
968+
self.env.clone(),
969+
false,
970+
) {
963971
function.call(())
964972
} else {
965973
self.call(())
@@ -978,7 +986,20 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
978986
/// This simply compiles the chunk without actually executing it.
979987
pub fn into_function(self) -> Result<Function<'lua>> {
980988
self.context
981-
.load_chunk(self.source, self.name.as_ref(), self.env)
989+
.load_chunk(self.source, self.name.as_ref(), self.env, false)
990+
}
991+
992+
/// Load this chunk into a regular `Function`.
993+
///
994+
/// This simply compiles the chunk without actually executing it.
995+
/// Unlike `into_function`, this method allows loading code previously
996+
/// compiled and saved with `Function::dump` or `string.dump()`.
997+
/// This method is unsafe because there is no check that the precompiled
998+
/// Lua code is valid; if it is not this may cause a crash or other
999+
/// undefined behaviour.
1000+
pub unsafe fn into_function_allow_binary(self) -> Result<Function<'lua>> {
1001+
self.context
1002+
.load_chunk(self.source, self.name.as_ref(), self.env, true)
9821003
}
9831004
}
9841005

src/function.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use std::os::raw::c_int;
22
use std::ptr;
33

4+
use libc::c_void;
5+
46
use crate::error::{Error, Result};
57
use crate::ffi;
68
use crate::types::LuaRef;
79
use crate::util::{
8-
assert_stack, check_stack, error_traceback, pop_error, protect_lua_closure, rotate, StackGuard,
10+
assert_stack, check_stack, dump, error_traceback, pop_error, protect_lua_closure, rotate,
11+
StackGuard,
912
};
1013
use crate::value::{FromLuaMulti, MultiValue, ToLuaMulti};
1114

@@ -161,4 +164,59 @@ impl<'lua> Function<'lua> {
161164
Ok(Function(lua.pop_ref()))
162165
}
163166
}
167+
168+
/// Dumps the compiled representation of the function into a binary blob,
169+
/// which can later be loaded using the unsafe Chunk::into_function_allow_binary().
170+
///
171+
/// # Examples
172+
///
173+
/// ```
174+
/// # use rlua::{Lua, Function, Result};
175+
/// # fn main() -> Result<()> {
176+
/// # Lua::new().context(|lua_context| {
177+
/// let add2: Function = lua_context.load(r#"
178+
/// function(a)
179+
/// return a + 2
180+
/// end
181+
/// "#).eval()?;
182+
///
183+
/// let dumped = add2.dump()?;
184+
///
185+
/// let reloaded = unsafe {
186+
/// lua_context.load(&dumped)
187+
/// .into_function_allow_binary()?
188+
/// };
189+
/// assert_eq!(reloaded.call::<_, u32>(7)?, 7+2);
190+
///
191+
/// # Ok(())
192+
/// # })
193+
/// # }
194+
/// ```
195+
pub fn dump(&self) -> Result<Vec<u8>> {
196+
unsafe extern "C" fn writer(
197+
_state: *mut ffi::lua_State,
198+
p: *const c_void,
199+
sz: usize,
200+
ud: *mut c_void,
201+
) -> c_int {
202+
let input_slice = std::slice::from_raw_parts(p as *const u8, sz);
203+
let vec = &mut *(ud as *mut Vec<u8>);
204+
vec.extend_from_slice(input_slice);
205+
0
206+
}
207+
let lua = self.0.lua;
208+
let mut bytes = Vec::new();
209+
unsafe {
210+
let _sg = StackGuard::new(lua.state);
211+
check_stack(lua.state, 1)?;
212+
let bytes_ptr = &mut bytes as *mut _;
213+
protect_lua_closure(lua.state, 0, 0, |state| {
214+
lua.push_ref(&self.0);
215+
let dump_result = dump(state, Some(writer), bytes_ptr as *mut c_void, 0);
216+
// It can only return an error from our writer.
217+
debug_assert_eq!(dump_result, 0);
218+
})?;
219+
}
220+
Ok(bytes)
221+
}
164222
}

0 commit comments

Comments
 (0)