Use u64 for operations counter.
This commit is contained in:
parent
1824dced69
commit
6b8c6bda42
@ -2347,7 +2347,7 @@ engine.set_max_modules(0); // allow unlimited modules
|
|||||||
|
|
||||||
### Maximum call stack depth
|
### Maximum call stack depth
|
||||||
|
|
||||||
Rhai by default limits function calls to a maximum depth of 128 levels (8 levels in debug build).
|
Rhai by default limits function calls to a maximum depth of 128 levels (16 levels in debug build).
|
||||||
This limit may be changed via the `Engine::set_max_call_levels` method.
|
This limit may be changed via the `Engine::set_max_call_levels` method.
|
||||||
|
|
||||||
When setting this limit, care must be also taken to the evaluation depth of each _statement_
|
When setting this limit, care must be also taken to the evaluation depth of each _statement_
|
||||||
|
@ -27,7 +27,7 @@ use crate::stdlib::{
|
|||||||
format,
|
format,
|
||||||
iter::{empty, once, repeat},
|
iter::{empty, once, repeat},
|
||||||
mem,
|
mem,
|
||||||
num::{NonZeroU64, NonZeroUsize},
|
num::NonZeroUsize,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
@ -49,7 +49,7 @@ pub type Map = HashMap<String, Dynamic>;
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
pub const MAX_CALL_STACK_DEPTH: usize = 8;
|
pub const MAX_CALL_STACK_DEPTH: usize = 16;
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
pub const MAX_EXPR_DEPTH: usize = 32;
|
pub const MAX_EXPR_DEPTH: usize = 32;
|
||||||
@ -354,16 +354,16 @@ pub struct Engine {
|
|||||||
pub(crate) optimization_level: OptimizationLevel,
|
pub(crate) optimization_level: OptimizationLevel,
|
||||||
/// Maximum levels of call-stack to prevent infinite recursion.
|
/// Maximum levels of call-stack to prevent infinite recursion.
|
||||||
///
|
///
|
||||||
/// Defaults to 8 for debug builds and 128 for non-debug builds.
|
/// Defaults to 16 for debug builds and 128 for non-debug builds.
|
||||||
pub(crate) max_call_stack_depth: usize,
|
pub(crate) max_call_stack_depth: usize,
|
||||||
/// Maximum depth of statements/expressions at global level.
|
/// Maximum depth of statements/expressions at global level.
|
||||||
pub(crate) max_expr_depth: usize,
|
pub(crate) max_expr_depth: usize,
|
||||||
/// Maximum depth of statements/expressions in functions.
|
/// Maximum depth of statements/expressions in functions.
|
||||||
pub(crate) max_function_expr_depth: usize,
|
pub(crate) max_function_expr_depth: usize,
|
||||||
/// Maximum number of operations allowed to run.
|
/// Maximum number of operations allowed to run.
|
||||||
pub(crate) max_operations: Option<NonZeroU64>,
|
pub(crate) max_operations: u64,
|
||||||
/// Maximum number of modules allowed to load.
|
/// Maximum number of modules allowed to load.
|
||||||
pub(crate) max_modules: Option<NonZeroU64>,
|
pub(crate) max_modules: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Engine {
|
impl Default for Engine {
|
||||||
@ -404,8 +404,8 @@ impl Default for Engine {
|
|||||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||||
max_expr_depth: MAX_EXPR_DEPTH,
|
max_expr_depth: MAX_EXPR_DEPTH,
|
||||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||||
max_operations: None,
|
max_operations: u64::MAX,
|
||||||
max_modules: None,
|
max_modules: u64::MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "no_stdlib")]
|
#[cfg(feature = "no_stdlib")]
|
||||||
@ -547,8 +547,8 @@ impl Engine {
|
|||||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||||
max_expr_depth: MAX_EXPR_DEPTH,
|
max_expr_depth: MAX_EXPR_DEPTH,
|
||||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||||
max_operations: None,
|
max_operations: u64::MAX,
|
||||||
max_modules: None,
|
max_modules: u64::MAX,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,13 +589,17 @@ impl Engine {
|
|||||||
/// consuming too much resources (0 for unlimited).
|
/// consuming too much resources (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn set_max_operations(&mut self, operations: u64) {
|
pub fn set_max_operations(&mut self, operations: u64) {
|
||||||
self.max_operations = NonZeroU64::new(operations);
|
self.max_operations = if operations == 0 {
|
||||||
|
u64::MAX
|
||||||
|
} else {
|
||||||
|
operations
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum number of imported modules allowed for a script (0 for unlimited).
|
/// Set the maximum number of imported modules allowed for a script (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn set_max_modules(&mut self, modules: u64) {
|
pub fn set_max_modules(&mut self, modules: u64) {
|
||||||
self.max_modules = NonZeroU64::new(modules);
|
self.max_modules = if modules == 0 { u64::MAX } else { modules };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the depth limits for expressions/statements.
|
/// Set the depth limits for expressions/statements.
|
||||||
@ -1835,11 +1839,9 @@ impl Engine {
|
|||||||
let (expr, (name, pos)) = x.as_ref();
|
let (expr, (name, pos)) = x.as_ref();
|
||||||
|
|
||||||
// Guard against too many modules
|
// Guard against too many modules
|
||||||
if let Some(max) = self.max_modules {
|
if state.modules >= self.max_modules {
|
||||||
if state.modules >= max.get() {
|
|
||||||
return Err(Box::new(EvalAltResult::ErrorTooManyModules(*pos)));
|
return Err(Box::new(EvalAltResult::ErrorTooManyModules(*pos)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(path) = self
|
if let Some(path) = self
|
||||||
.eval_expr(scope, state, &expr, level)?
|
.eval_expr(scope, state, &expr, level)?
|
||||||
@ -1902,12 +1904,10 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
// Guard against too many operations
|
// Guard against too many operations
|
||||||
if let Some(max) = self.max_operations {
|
if state.operations > self.max_operations {
|
||||||
if state.operations > max.get() {
|
|
||||||
return Err(Box::new(EvalAltResult::ErrorTooManyOperations(pos)));
|
return Err(Box::new(EvalAltResult::ErrorTooManyOperations(pos)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Report progress - only in steps
|
// Report progress - only in steps
|
||||||
if let Some(progress) = &self.progress {
|
if let Some(progress) = &self.progress {
|
||||||
|
@ -86,14 +86,14 @@ fn test_module_resolver() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.eval::<INT>(
|
.eval::<INT>(
|
||||||
r#"
|
r#"
|
||||||
let x = 0;
|
let sum = 0;
|
||||||
|
|
||||||
for x in range(0, 10) {
|
for x in range(0, 10) {
|
||||||
import "hello" as h;
|
import "hello" as h;
|
||||||
x += h::answer;
|
sum += h::answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
x
|
sum
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
@ -105,18 +105,18 @@ fn test_module_resolver() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.eval::<INT>(
|
.eval::<INT>(
|
||||||
r#"
|
r#"
|
||||||
let x = 0;
|
let sum = 0;
|
||||||
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
import "hello" as h;
|
import "hello" as h;
|
||||||
x += h::answer;
|
sum += h::answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
for x in range(0, 10) {
|
for x in range(0, 10) {
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
|
|
||||||
x
|
sum
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
|
@ -16,19 +16,14 @@ fn test_stack_overflow_fn_calls() -> Result<(), Box<EvalAltResult>> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
match engine.eval::<()>(
|
assert!(matches!(
|
||||||
|
*engine.eval::<()>(
|
||||||
r"
|
r"
|
||||||
fn foo(n) { if n == 0 { 0 } else { n + foo(n-1) } }
|
fn foo(n) { if n == 0 { 0 } else { n + foo(n-1) } }
|
||||||
foo(1000)
|
foo(1000)
|
||||||
",
|
").expect_err("should error"),
|
||||||
) {
|
EvalAltResult::ErrorInFunctionCall(name, _, _) if name.starts_with("foo > foo > foo")
|
||||||
Ok(_) => panic!("should be stack overflow"),
|
));
|
||||||
Err(err) => match *err {
|
|
||||||
EvalAltResult::ErrorInFunctionCall(name, _, _)
|
|
||||||
if name.starts_with("foo > foo > foo") => {}
|
|
||||||
_ => panic!("should be stack overflow"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user