2022-02-19 09:15:15 -05:00
|
|
|
#![cfg(not(feature = "luau"))]
|
|
|
|
|
2020-05-21 19:35:03 -04:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::ops::Deref;
|
|
|
|
use std::str;
|
2022-03-30 18:55:34 -04:00
|
|
|
use std::sync::atomic::{AtomicI64, Ordering};
|
2020-05-21 19:35:03 -04:00
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
|
2021-08-17 10:17:03 -04:00
|
|
|
use mlua::{DebugEvent, Error, HookTriggers, Lua, Result, Value};
|
2020-05-21 19:35:03 -04:00
|
|
|
|
2021-08-18 13:49:17 -04:00
|
|
|
#[test]
|
|
|
|
fn test_hook_triggers_bitor() {
|
|
|
|
let trigger = HookTriggers::on_calls()
|
|
|
|
| HookTriggers::on_returns()
|
|
|
|
| HookTriggers::every_line()
|
|
|
|
| HookTriggers::every_nth_instruction(5);
|
|
|
|
|
|
|
|
assert!(trigger.on_calls);
|
|
|
|
assert!(trigger.on_returns);
|
|
|
|
assert!(trigger.every_line);
|
|
|
|
assert_eq!(trigger.every_nth_instruction, Some(5));
|
|
|
|
}
|
|
|
|
|
2020-05-21 19:35:03 -04:00
|
|
|
#[test]
|
2021-06-18 18:13:56 -04:00
|
|
|
fn test_line_counts() -> Result<()> {
|
2020-05-21 19:35:03 -04:00
|
|
|
let output = Arc::new(Mutex::new(Vec::new()));
|
|
|
|
let hook_output = output.clone();
|
|
|
|
|
|
|
|
let lua = Lua::new();
|
2021-08-18 13:49:17 -04:00
|
|
|
lua.set_hook(HookTriggers::every_line(), move |_lua, debug| {
|
|
|
|
assert_eq!(debug.event(), DebugEvent::Line);
|
|
|
|
hook_output.lock().unwrap().push(debug.curr_line());
|
|
|
|
Ok(())
|
|
|
|
})?;
|
2020-05-21 19:35:03 -04:00
|
|
|
lua.load(
|
|
|
|
r#"
|
|
|
|
local x = 2 + 3
|
|
|
|
local y = x * 63
|
|
|
|
local z = string.len(x..", "..y)
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.exec()?;
|
|
|
|
|
2020-06-07 14:10:46 -04:00
|
|
|
lua.remove_hook();
|
|
|
|
|
2020-05-21 19:35:03 -04:00
|
|
|
let output = output.lock().unwrap();
|
2020-06-07 14:10:46 -04:00
|
|
|
if cfg!(feature = "luajit") && lua.load("jit.version_num").eval::<i64>()? >= 20100 {
|
|
|
|
assert_eq!(*output, vec![2, 3, 4, 0, 4]);
|
|
|
|
} else {
|
|
|
|
assert_eq!(*output, vec![2, 3, 4]);
|
|
|
|
}
|
2020-05-21 19:35:03 -04:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-06-18 18:13:56 -04:00
|
|
|
fn test_function_calls() -> Result<()> {
|
2020-05-21 19:35:03 -04:00
|
|
|
let output = Arc::new(Mutex::new(Vec::new()));
|
|
|
|
let hook_output = output.clone();
|
|
|
|
|
|
|
|
let lua = Lua::new();
|
2021-08-18 13:49:17 -04:00
|
|
|
lua.set_hook(HookTriggers::on_calls(), move |_lua, debug| {
|
|
|
|
assert_eq!(debug.event(), DebugEvent::Call);
|
|
|
|
let names = debug.names();
|
|
|
|
let source = debug.source();
|
|
|
|
let name = names.name.map(|s| str::from_utf8(s).unwrap().to_owned());
|
|
|
|
let what = source.what.map(|s| str::from_utf8(s).unwrap().to_owned());
|
|
|
|
hook_output.lock().unwrap().push((name, what));
|
|
|
|
Ok(())
|
|
|
|
})?;
|
2020-05-21 19:35:03 -04:00
|
|
|
|
|
|
|
lua.load(
|
|
|
|
r#"
|
|
|
|
local v = string.len("Hello World")
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.exec()?;
|
|
|
|
|
2020-06-07 14:10:46 -04:00
|
|
|
lua.remove_hook();
|
|
|
|
|
2020-05-21 19:35:03 -04:00
|
|
|
let output = output.lock().unwrap();
|
2020-06-07 14:10:46 -04:00
|
|
|
if cfg!(feature = "luajit") && lua.load("jit.version_num").eval::<i64>()? >= 20100 {
|
|
|
|
assert_eq!(
|
|
|
|
*output,
|
|
|
|
vec![
|
|
|
|
(None, Some("main".to_string())),
|
|
|
|
(Some("len".to_string()), Some("Lua".to_string()))
|
|
|
|
]
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
assert_eq!(
|
|
|
|
*output,
|
|
|
|
vec![
|
|
|
|
(None, Some("main".to_string())),
|
|
|
|
(Some("len".to_string()), Some("C".to_string()))
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
2020-05-21 19:35:03 -04:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-06-18 18:13:56 -04:00
|
|
|
fn test_error_within_hook() -> Result<()> {
|
2020-05-21 19:35:03 -04:00
|
|
|
let lua = Lua::new();
|
2021-08-18 13:49:17 -04:00
|
|
|
|
|
|
|
lua.set_hook(HookTriggers::every_line(), |_lua, _debug| {
|
|
|
|
Err(Error::RuntimeError(
|
|
|
|
"Something happened in there!".to_string(),
|
|
|
|
))
|
|
|
|
})?;
|
2020-05-21 19:35:03 -04:00
|
|
|
|
|
|
|
let err = lua
|
|
|
|
.load("x = 1")
|
|
|
|
.exec()
|
|
|
|
.expect_err("panic didn't propagate");
|
|
|
|
|
|
|
|
match err {
|
|
|
|
Error::CallbackError { cause, .. } => match cause.deref() {
|
|
|
|
Error::RuntimeError(s) => assert_eq!(s, "Something happened in there!"),
|
|
|
|
_ => panic!("wrong callback error kind caught"),
|
|
|
|
},
|
|
|
|
_ => panic!("wrong error kind caught"),
|
|
|
|
};
|
2020-06-07 10:16:12 -04:00
|
|
|
|
|
|
|
Ok(())
|
2020-05-21 19:35:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-06-18 18:13:56 -04:00
|
|
|
fn test_limit_execution_instructions() -> Result<()> {
|
2020-05-21 19:35:03 -04:00
|
|
|
let lua = Lua::new();
|
|
|
|
|
2020-06-07 14:10:46 -04:00
|
|
|
// For LuaJIT disable JIT, as compiled code does not trigger hooks
|
2022-03-30 18:55:34 -04:00
|
|
|
#[cfg(feature = "luajit")]
|
2020-06-07 14:10:46 -04:00
|
|
|
lua.load("jit.off()").exec()?;
|
|
|
|
|
2022-03-30 18:55:34 -04:00
|
|
|
let max_instructions = AtomicI64::new(10000);
|
2020-05-21 19:35:03 -04:00
|
|
|
lua.set_hook(
|
2021-08-18 13:49:17 -04:00
|
|
|
HookTriggers::every_nth_instruction(30),
|
2021-08-17 10:17:03 -04:00
|
|
|
move |_lua, debug| {
|
|
|
|
assert_eq!(debug.event(), DebugEvent::Count);
|
2022-03-30 18:55:34 -04:00
|
|
|
if max_instructions.fetch_sub(30, Ordering::Relaxed) <= 30 {
|
2020-05-21 19:35:03 -04:00
|
|
|
Err(Error::RuntimeError("time's up".to_string()))
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
},
|
2020-06-07 10:16:12 -04:00
|
|
|
)?;
|
2020-05-21 19:35:03 -04:00
|
|
|
|
2020-06-07 10:16:12 -04:00
|
|
|
lua.globals().set("x", Value::Integer(0))?;
|
2020-05-21 19:35:03 -04:00
|
|
|
let _ = lua
|
|
|
|
.load(
|
|
|
|
r#"
|
|
|
|
for i = 1, 10000 do
|
|
|
|
x = x + 1
|
|
|
|
end
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.exec()
|
|
|
|
.expect_err("instruction limit didn't occur");
|
2020-06-07 10:16:12 -04:00
|
|
|
|
|
|
|
Ok(())
|
2020-05-21 19:35:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-06-18 18:13:56 -04:00
|
|
|
fn test_hook_removal() -> Result<()> {
|
2020-05-21 19:35:03 -04:00
|
|
|
let lua = Lua::new();
|
|
|
|
|
2021-08-18 13:49:17 -04:00
|
|
|
lua.set_hook(HookTriggers::every_nth_instruction(1), |_lua, _debug| {
|
|
|
|
Err(Error::RuntimeError(
|
|
|
|
"this hook should've been removed by this time".to_string(),
|
|
|
|
))
|
|
|
|
})?;
|
2020-05-21 19:35:03 -04:00
|
|
|
|
|
|
|
assert!(lua.load("local x = 1").exec().is_err());
|
|
|
|
lua.remove_hook();
|
|
|
|
assert!(lua.load("local x = 1").exec().is_ok());
|
2020-06-07 10:16:12 -04:00
|
|
|
|
|
|
|
Ok(())
|
2020-05-21 19:35:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-06-18 18:13:56 -04:00
|
|
|
fn test_hook_swap_within_hook() -> Result<()> {
|
2020-05-21 19:35:03 -04:00
|
|
|
thread_local! {
|
|
|
|
static TL_LUA: RefCell<Option<Lua>> = RefCell::new(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
TL_LUA.with(|tl| {
|
|
|
|
*tl.borrow_mut() = Some(Lua::new());
|
|
|
|
});
|
|
|
|
|
|
|
|
TL_LUA.with(|tl| {
|
2021-08-18 13:49:17 -04:00
|
|
|
tl.borrow()
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.set_hook(HookTriggers::every_line(), move |lua, _debug| {
|
2020-06-07 10:16:12 -04:00
|
|
|
lua.globals().set("ok", 1i64)?;
|
2020-05-21 19:35:03 -04:00
|
|
|
TL_LUA.with(|tl| {
|
|
|
|
tl.borrow().as_ref().unwrap().set_hook(
|
2021-08-18 13:49:17 -04:00
|
|
|
HookTriggers::every_line(),
|
2020-05-21 19:35:03 -04:00
|
|
|
move |lua, _debug| {
|
|
|
|
lua.load(
|
|
|
|
r#"
|
|
|
|
if ok ~= nil then
|
|
|
|
ok = ok + 1
|
|
|
|
end
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.exec()
|
|
|
|
.expect("exec failure within hook");
|
|
|
|
TL_LUA.with(|tl| {
|
|
|
|
tl.borrow().as_ref().unwrap().remove_hook();
|
|
|
|
});
|
|
|
|
Ok(())
|
|
|
|
},
|
2020-06-07 10:16:12 -04:00
|
|
|
)
|
|
|
|
})
|
2021-08-18 13:49:17 -04:00
|
|
|
})
|
2020-06-07 10:16:12 -04:00
|
|
|
})?;
|
2020-05-21 19:35:03 -04:00
|
|
|
|
|
|
|
TL_LUA.with(|tl| {
|
|
|
|
let tl = tl.borrow();
|
|
|
|
let lua = tl.as_ref().unwrap();
|
2020-06-07 10:16:12 -04:00
|
|
|
lua.load(
|
|
|
|
r#"
|
|
|
|
local x = 1
|
|
|
|
x = 2
|
|
|
|
local y = 3
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.exec()?;
|
|
|
|
assert_eq!(lua.globals().get::<_, i64>("ok")?, 2);
|
|
|
|
Ok(())
|
|
|
|
})
|
2020-05-21 19:35:03 -04:00
|
|
|
}
|