Use NonZero for limits.
This commit is contained in:
parent
3fbcefe0ed
commit
a5d6392107
138
src/engine.rs
138
src/engine.rs
@ -135,7 +135,8 @@ impl Imports {
|
|||||||
.rev()
|
.rev()
|
||||||
.find_map(|(_, m)| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
|
.find_map(|(_, m)| m.get_qualified_fn(hash).map(|f| (f, m.id_raw())))
|
||||||
}
|
}
|
||||||
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of imported [modules][Module]?
|
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of
|
||||||
|
/// imported [modules][Module]?
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn contains_iter(&self, id: TypeId) -> bool {
|
pub fn contains_iter(&self, id: TypeId) -> bool {
|
||||||
@ -508,8 +509,8 @@ pub struct State {
|
|||||||
/// In some situation, e.g. after running an `eval` statement, subsequent offsets become mis-aligned.
|
/// In some situation, e.g. after running an `eval` statement, subsequent offsets become mis-aligned.
|
||||||
/// When that happens, this flag is turned on to force a scope lookup by name.
|
/// When that happens, this flag is turned on to force a scope lookup by name.
|
||||||
pub always_search: bool,
|
pub always_search: bool,
|
||||||
/// Level of the current scope. The global (root) level is zero, a new block (or function call)
|
/// Level of the current scope. The global (root) level is zero, a new block
|
||||||
/// is one level higher, and so on.
|
/// (or function call) is one level higher, and so on.
|
||||||
pub scope_level: usize,
|
pub scope_level: usize,
|
||||||
/// Number of operations performed.
|
/// Number of operations performed.
|
||||||
pub operations: u64,
|
pub operations: u64,
|
||||||
@ -542,30 +543,34 @@ impl State {
|
|||||||
pub struct Limits {
|
pub struct Limits {
|
||||||
/// Maximum levels of call-stack to prevent infinite recursion.
|
/// Maximum levels of call-stack to prevent infinite recursion.
|
||||||
/// Not available under `no_function`.
|
/// Not available under `no_function`.
|
||||||
|
///
|
||||||
|
/// Set to zero to effectively disable function calls.
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub max_call_stack_depth: usize,
|
pub max_call_stack_depth: usize,
|
||||||
/// Maximum depth of statements/expressions at global level (0 = unlimited).
|
/// Maximum depth of statements/expressions at global level.
|
||||||
pub max_expr_depth: usize,
|
pub max_expr_depth: Option<NonZeroUsize>,
|
||||||
/// Maximum depth of statements/expressions in functions (0 = unlimited).
|
/// Maximum depth of statements/expressions in functions.
|
||||||
/// Not available under `no_function`.
|
/// Not available under `no_function`.
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub max_function_expr_depth: usize,
|
pub max_function_expr_depth: Option<NonZeroUsize>,
|
||||||
/// Maximum number of operations allowed to run (0 = unlimited).
|
/// Maximum number of operations allowed to run.
|
||||||
pub max_operations: u64,
|
pub max_operations: Option<NonZeroU64>,
|
||||||
/// Maximum number of [modules][Module] allowed to load.
|
/// Maximum number of [modules][Module] allowed to load.
|
||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
|
///
|
||||||
|
/// Set to zero to effectively disable loading any [module][Module].
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub max_modules: usize,
|
pub max_modules: usize,
|
||||||
/// Maximum length of a [string][ImmutableString] (0 = unlimited).
|
/// Maximum length of a [string][ImmutableString].
|
||||||
pub max_string_size: usize,
|
pub max_string_size: Option<NonZeroUsize>,
|
||||||
/// Maximum length of an [array][Array] (0 = unlimited).
|
/// Maximum length of an [array][Array].
|
||||||
/// Not available under `no_index`.
|
/// Not available under `no_index`.
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub max_array_size: usize,
|
pub max_array_size: Option<NonZeroUsize>,
|
||||||
/// Maximum number of properties in an [object map][Map] (0 = unlimited).
|
/// Maximum number of properties in an [object map][Map].
|
||||||
/// Not available under `no_object`.
|
/// Not available under `no_object`.
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub max_map_size: usize,
|
pub max_map_size: Option<NonZeroUsize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Context of a script evaluation process.
|
/// Context of a script evaluation process.
|
||||||
@ -777,13 +782,13 @@ pub fn search_imports(
|
|||||||
|
|
||||||
// Qualified - check if the root module is directly indexed
|
// Qualified - check if the root module is directly indexed
|
||||||
let index = if state.always_search {
|
let index = if state.always_search {
|
||||||
0
|
None
|
||||||
} else {
|
} else {
|
||||||
namespace.index().map_or(0, NonZeroUsize::get)
|
namespace.index()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(if index > 0 {
|
Ok(if let Some(index) = index {
|
||||||
let offset = mods.len() - index;
|
let offset = mods.len() - index.get();
|
||||||
mods.get(offset).expect("invalid index in Imports")
|
mods.get(offset).expect("invalid index in Imports")
|
||||||
} else {
|
} else {
|
||||||
mods.find(root)
|
mods.find(root)
|
||||||
@ -838,17 +843,17 @@ impl Engine {
|
|||||||
limits: Limits {
|
limits: Limits {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
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: NonZeroUsize::new(MAX_EXPR_DEPTH),
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
max_function_expr_depth: NonZeroUsize::new(MAX_FUNCTION_EXPR_DEPTH),
|
||||||
max_operations: 0,
|
max_operations: None,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
max_modules: usize::MAX,
|
max_modules: usize::MAX,
|
||||||
max_string_size: 0,
|
max_string_size: None,
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
max_array_size: 0,
|
max_array_size: None,
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
max_map_size: 0,
|
max_map_size: None,
|
||||||
},
|
},
|
||||||
|
|
||||||
disable_doc_comments: false,
|
disable_doc_comments: false,
|
||||||
@ -895,17 +900,17 @@ impl Engine {
|
|||||||
limits: Limits {
|
limits: Limits {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
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: NonZeroUsize::new(MAX_EXPR_DEPTH),
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
max_function_expr_depth: NonZeroUsize::new(MAX_FUNCTION_EXPR_DEPTH),
|
||||||
max_operations: 0,
|
max_operations: None,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
max_modules: usize::MAX,
|
max_modules: usize::MAX,
|
||||||
max_string_size: 0,
|
max_string_size: None,
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
max_array_size: 0,
|
max_array_size: None,
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
max_map_size: 0,
|
max_map_size: None,
|
||||||
},
|
},
|
||||||
|
|
||||||
disable_doc_comments: false,
|
disable_doc_comments: false,
|
||||||
@ -975,14 +980,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if it is directly indexed
|
// Check if it is directly indexed
|
||||||
let index = if state.always_search {
|
let index = if state.always_search { &None } else { index };
|
||||||
0
|
|
||||||
} else {
|
|
||||||
index.map_or(0, NonZeroUsize::get)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check the variable resolver, if any
|
// Check the variable resolver, if any
|
||||||
if let Some(ref resolve_var) = self.resolve_var {
|
if let Some(ref resolve_var) = self.resolve_var {
|
||||||
|
let index = index.map(NonZeroUsize::get).unwrap_or(0);
|
||||||
let context = EvalContext {
|
let context = EvalContext {
|
||||||
engine: self,
|
engine: self,
|
||||||
scope,
|
scope,
|
||||||
@ -1000,8 +1002,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = if index > 0 {
|
let index = if let Some(index) = index {
|
||||||
scope.len() - index
|
scope.len() - index.get()
|
||||||
} else {
|
} else {
|
||||||
// Find the variable in the scope
|
// Find the variable in the scope
|
||||||
scope
|
scope
|
||||||
@ -1012,8 +1014,8 @@ impl Engine {
|
|||||||
|
|
||||||
let val = scope.get_mut_by_index(index);
|
let val = scope.get_mut_by_index(index);
|
||||||
|
|
||||||
// Check for data race - probably not necessary because the only place it should conflict is in a method call
|
// Check for data race - probably not necessary because the only place it should conflict is
|
||||||
// when the object variable is also used as a parameter.
|
// in a method call when the object variable is also used as a parameter.
|
||||||
// if cfg!(not(feature = "no_closure")) && val.is_locked() {
|
// if cfg!(not(feature = "no_closure")) && val.is_locked() {
|
||||||
// return EvalAltResult::ErrorDataRace(name.into(), *pos).into();
|
// return EvalAltResult::ErrorDataRace(name.into(), *pos).into();
|
||||||
// }
|
// }
|
||||||
@ -1285,7 +1287,8 @@ impl Engine {
|
|||||||
)
|
)
|
||||||
.or_else(
|
.or_else(
|
||||||
|err| match *err {
|
|err| match *err {
|
||||||
// If there is no setter, no need to feed it back because the property is read-only
|
// If there is no setter, no need to feed it back because
|
||||||
|
// the property is read-only
|
||||||
EvalAltResult::ErrorDotExpr(_, _) => {
|
EvalAltResult::ErrorDotExpr(_, _) => {
|
||||||
Ok((Dynamic::UNIT, false))
|
Ok((Dynamic::UNIT, false))
|
||||||
}
|
}
|
||||||
@ -1405,7 +1408,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a chain of indexes and store the results in a [`StaticVec`].
|
/// Evaluate a chain of indexes and store the results in a [`StaticVec`].
|
||||||
/// [`StaticVec`] is used to avoid an allocation in the overwhelming cases of just a few levels of indexing.
|
/// [`StaticVec`] is used to avoid an allocation in the overwhelming cases of
|
||||||
|
/// just a few levels of indexing.
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
fn eval_indexed_chain(
|
fn eval_indexed_chain(
|
||||||
&self,
|
&self,
|
||||||
@ -2400,20 +2404,23 @@ impl Engine {
|
|||||||
result: Result<Dynamic, Box<EvalAltResult>>,
|
result: Result<Dynamic, Box<EvalAltResult>>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
// If no data size limits, just return
|
// Simply return all errors
|
||||||
let mut total = 0;
|
if result.is_err() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
total += self.max_string_size();
|
// If no data size limits, just return
|
||||||
|
let mut has_limit = self.limits.max_string_size.is_some();
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
total += self.max_array_size();
|
has_limit = has_limit || self.limits.max_array_size.is_some();
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
total += self.max_map_size();
|
has_limit = has_limit || self.limits.max_map_size.is_some();
|
||||||
}
|
}
|
||||||
|
|
||||||
if total == 0 {
|
if !has_limit {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2469,34 +2476,33 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match result {
|
|
||||||
// Simply return all errors
|
|
||||||
Err(_) => return result,
|
|
||||||
// String with limit
|
|
||||||
Ok(Dynamic(Union::Str(_, _))) if self.max_string_size() > 0 => (),
|
|
||||||
// Array with limit
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
Ok(Dynamic(Union::Array(_, _))) if self.max_array_size() > 0 => (),
|
|
||||||
// Map with limit
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
Ok(Dynamic(Union::Map(_, _))) if self.max_map_size() > 0 => (),
|
|
||||||
// Everything else is simply returned
|
|
||||||
Ok(_) => return result,
|
|
||||||
};
|
|
||||||
|
|
||||||
let (_arr, _map, s) = calc_size(result.as_ref().unwrap());
|
let (_arr, _map, s) = calc_size(result.as_ref().unwrap());
|
||||||
|
|
||||||
if s > self.max_string_size() {
|
if s > self
|
||||||
|
.limits
|
||||||
|
.max_string_size
|
||||||
|
.map_or(usize::MAX, NonZeroUsize::get)
|
||||||
|
{
|
||||||
return EvalAltResult::ErrorDataTooLarge("Length of string".to_string(), pos).into();
|
return EvalAltResult::ErrorDataTooLarge("Length of string".to_string(), pos).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
if _arr > self.max_array_size() {
|
if _arr
|
||||||
|
> self
|
||||||
|
.limits
|
||||||
|
.max_array_size
|
||||||
|
.map_or(usize::MAX, NonZeroUsize::get)
|
||||||
|
{
|
||||||
return EvalAltResult::ErrorDataTooLarge("Size of array".to_string(), pos).into();
|
return EvalAltResult::ErrorDataTooLarge("Size of array".to_string(), pos).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
if _map > self.max_map_size() {
|
if _map
|
||||||
|
> self
|
||||||
|
.limits
|
||||||
|
.max_map_size
|
||||||
|
.map_or(usize::MAX, NonZeroUsize::get)
|
||||||
|
{
|
||||||
return EvalAltResult::ErrorDataTooLarge("Size of object map".to_string(), pos).into();
|
return EvalAltResult::ErrorDataTooLarge("Size of object map".to_string(), pos).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
//! Configuration settings for [`Engine`].
|
//! Configuration settings for [`Engine`].
|
||||||
|
|
||||||
use crate::stdlib::{format, num::NonZeroU8, string::String};
|
use crate::stdlib::{
|
||||||
|
format,
|
||||||
|
num::{NonZeroU64, NonZeroU8, NonZeroUsize},
|
||||||
|
string::String,
|
||||||
|
};
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::Engine;
|
use crate::Engine;
|
||||||
|
|
||||||
@ -62,11 +66,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_max_operations(&mut self, operations: u64) -> &mut Self {
|
pub fn set_max_operations(&mut self, operations: u64) -> &mut Self {
|
||||||
self.limits.max_operations = if operations == u64::MAX {
|
self.limits.max_operations = NonZeroU64::new(operations);
|
||||||
0
|
|
||||||
} else {
|
|
||||||
operations
|
|
||||||
};
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// The maximum number of operations allowed for a script to run (0 for unlimited).
|
/// The maximum number of operations allowed for a script to run (0 for unlimited).
|
||||||
@ -75,7 +75,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_operations(&self) -> u64 {
|
pub fn max_operations(&self) -> u64 {
|
||||||
self.limits.max_operations
|
self.limits.max_operations.map_or(0, NonZeroU64::get)
|
||||||
}
|
}
|
||||||
/// Set the maximum number of imported [modules][crate::Module] allowed for a script.
|
/// Set the maximum number of imported [modules][crate::Module] allowed for a script.
|
||||||
///
|
///
|
||||||
@ -106,18 +106,10 @@ impl Engine {
|
|||||||
max_expr_depth: usize,
|
max_expr_depth: usize,
|
||||||
#[cfg(not(feature = "no_function"))] max_function_expr_depth: usize,
|
#[cfg(not(feature = "no_function"))] max_function_expr_depth: usize,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.limits.max_expr_depth = if max_expr_depth == usize::MAX {
|
self.limits.max_expr_depth = NonZeroUsize::new(max_expr_depth);
|
||||||
0
|
|
||||||
} else {
|
|
||||||
max_expr_depth
|
|
||||||
};
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
{
|
{
|
||||||
self.limits.max_function_expr_depth = if max_function_expr_depth == usize::MAX {
|
self.limits.max_function_expr_depth = NonZeroUsize::new(max_function_expr_depth);
|
||||||
0
|
|
||||||
} else {
|
|
||||||
max_function_expr_depth
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -127,7 +119,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_expr_depth(&self) -> usize {
|
pub fn max_expr_depth(&self) -> usize {
|
||||||
self.limits.max_expr_depth
|
self.limits.max_expr_depth.map_or(0, NonZeroUsize::get)
|
||||||
}
|
}
|
||||||
/// The depth limit for expressions in functions (0 for unlimited).
|
/// The depth limit for expressions in functions (0 for unlimited).
|
||||||
///
|
///
|
||||||
@ -136,7 +128,9 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_function_expr_depth(&self) -> usize {
|
pub fn max_function_expr_depth(&self) -> usize {
|
||||||
self.limits.max_function_expr_depth
|
self.limits
|
||||||
|
.max_function_expr_depth
|
||||||
|
.map_or(0, NonZeroUsize::get)
|
||||||
}
|
}
|
||||||
/// Set the maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
/// Set the maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
||||||
///
|
///
|
||||||
@ -144,7 +138,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self {
|
pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self {
|
||||||
self.limits.max_string_size = if max_size == usize::MAX { 0 } else { max_size };
|
self.limits.max_string_size = NonZeroUsize::new(max_size);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// The maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
/// The maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
||||||
@ -153,7 +147,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_string_size(&self) -> usize {
|
pub fn max_string_size(&self) -> usize {
|
||||||
self.limits.max_string_size
|
self.limits.max_string_size.map_or(0, NonZeroUsize::get)
|
||||||
}
|
}
|
||||||
/// Set the maximum length of [arrays][crate::Array] (0 for unlimited).
|
/// Set the maximum length of [arrays][crate::Array] (0 for unlimited).
|
||||||
///
|
///
|
||||||
@ -162,7 +156,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self {
|
pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self {
|
||||||
self.limits.max_array_size = if max_size == usize::MAX { 0 } else { max_size };
|
self.limits.max_array_size = NonZeroUsize::new(max_size);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// The maximum length of [arrays][crate::Array] (0 for unlimited).
|
/// The maximum length of [arrays][crate::Array] (0 for unlimited).
|
||||||
@ -172,7 +166,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_array_size(&self) -> usize {
|
pub fn max_array_size(&self) -> usize {
|
||||||
self.limits.max_array_size
|
self.limits.max_array_size.map_or(0, NonZeroUsize::get)
|
||||||
}
|
}
|
||||||
/// Set the maximum size of [object maps][crate::Map] (0 for unlimited).
|
/// Set the maximum size of [object maps][crate::Map] (0 for unlimited).
|
||||||
///
|
///
|
||||||
@ -181,7 +175,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self {
|
pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self {
|
||||||
self.limits.max_map_size = if max_size == usize::MAX { 0 } else { max_size };
|
self.limits.max_map_size = NonZeroUsize::new(max_size);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// The maximum size of [object maps][crate::Map] (0 for unlimited).
|
/// The maximum size of [object maps][crate::Map] (0 for unlimited).
|
||||||
@ -191,7 +185,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_map_size(&self) -> usize {
|
pub fn max_map_size(&self) -> usize {
|
||||||
self.limits.max_map_size
|
self.limits.max_map_size.map_or(0, NonZeroUsize::get)
|
||||||
}
|
}
|
||||||
/// Set the module resolution service used by the [`Engine`].
|
/// Set the module resolution service used by the [`Engine`].
|
||||||
///
|
///
|
||||||
|
@ -61,11 +61,11 @@ struct ParseState<'e> {
|
|||||||
modules: StaticVec<ImmutableString>,
|
modules: StaticVec<ImmutableString>,
|
||||||
/// Maximum levels of expression nesting.
|
/// Maximum levels of expression nesting.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_expr_depth: usize,
|
max_expr_depth: Option<NonZeroUsize>,
|
||||||
/// Maximum levels of expression nesting in functions.
|
/// Maximum levels of expression nesting in functions.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
max_function_expr_depth: usize,
|
max_function_expr_depth: Option<NonZeroUsize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e> ParseState<'e> {
|
impl<'e> ParseState<'e> {
|
||||||
@ -73,10 +73,10 @@ impl<'e> ParseState<'e> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
#[cfg(not(feature = "unchecked"))] max_expr_depth: usize,
|
#[cfg(not(feature = "unchecked"))] max_expr_depth: Option<NonZeroUsize>,
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
max_function_expr_depth: usize,
|
max_function_expr_depth: Option<NonZeroUsize>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
@ -212,15 +212,17 @@ impl ParseSettings {
|
|||||||
}
|
}
|
||||||
/// Make sure that the current level of expression nesting is within the maximum limit.
|
/// Make sure that the current level of expression nesting is within the maximum limit.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub fn ensure_level_within_max_limit(&self, limit: usize) -> Result<(), ParseError> {
|
pub fn ensure_level_within_max_limit(
|
||||||
if limit == 0 {
|
&self,
|
||||||
Ok(())
|
limit: Option<NonZeroUsize>,
|
||||||
} else if self.level > limit {
|
) -> Result<(), ParseError> {
|
||||||
Err(PERR::ExprTooDeep.into_err(self.pos))
|
if let Some(limit) = limit {
|
||||||
} else {
|
if self.level > limit.get() {
|
||||||
Ok(())
|
return Err(PERR::ExprTooDeep.into_err(self.pos));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3040,10 +3042,10 @@ impl Engine {
|
|||||||
let mut state = ParseState::new(
|
let mut state = ParseState::new(
|
||||||
self,
|
self,
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.max_expr_depth(),
|
NonZeroUsize::new(self.max_expr_depth()),
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
self.max_function_expr_depth(),
|
NonZeroUsize::new(self.max_function_expr_depth()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
@ -3087,10 +3089,10 @@ impl Engine {
|
|||||||
let mut state = ParseState::new(
|
let mut state = ParseState::new(
|
||||||
self,
|
self,
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.max_expr_depth(),
|
NonZeroUsize::new(self.max_expr_depth()),
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
self.max_function_expr_depth(),
|
NonZeroUsize::new(self.max_function_expr_depth()),
|
||||||
);
|
);
|
||||||
|
|
||||||
while !input.peek().unwrap().0.is_eof() {
|
while !input.peek().unwrap().0.is_eof() {
|
||||||
|
15
src/token.rs
15
src/token.rs
@ -8,6 +8,7 @@ use crate::stdlib::{
|
|||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
char, fmt, format,
|
char, fmt, format,
|
||||||
iter::Peekable,
|
iter::Peekable,
|
||||||
|
num::NonZeroUsize,
|
||||||
str::{Chars, FromStr},
|
str::{Chars, FromStr},
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
};
|
};
|
||||||
@ -747,7 +748,7 @@ impl From<Token> for String {
|
|||||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||||
pub struct TokenizeState {
|
pub struct TokenizeState {
|
||||||
/// Maximum length of a string (0 = unlimited).
|
/// Maximum length of a string (0 = unlimited).
|
||||||
pub max_string_size: usize,
|
pub max_string_size: Option<NonZeroUsize>,
|
||||||
/// Can the next token be a unary operator?
|
/// Can the next token be a unary operator?
|
||||||
pub non_unary: bool,
|
pub non_unary: bool,
|
||||||
/// Is the tokenizer currently inside a block comment?
|
/// Is the tokenizer currently inside a block comment?
|
||||||
@ -796,8 +797,10 @@ pub fn parse_string_literal(
|
|||||||
|
|
||||||
pos.advance();
|
pos.advance();
|
||||||
|
|
||||||
if state.max_string_size > 0 && result.len() > state.max_string_size {
|
if let Some(max) = state.max_string_size {
|
||||||
return Err((LexError::StringTooLong(state.max_string_size), *pos));
|
if result.len() > max.get() {
|
||||||
|
return Err((LexError::StringTooLong(max.get()), *pos));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match next_char {
|
match next_char {
|
||||||
@ -902,8 +905,10 @@ pub fn parse_string_literal(
|
|||||||
|
|
||||||
let s = result.iter().collect::<String>();
|
let s = result.iter().collect::<String>();
|
||||||
|
|
||||||
if state.max_string_size > 0 && s.len() > state.max_string_size {
|
if let Some(max) = state.max_string_size {
|
||||||
return Err((LexError::StringTooLong(state.max_string_size), *pos));
|
if s.len() > max.get() {
|
||||||
|
return Err((LexError::StringTooLong(max.get()), *pos));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(s)
|
Ok(s)
|
||||||
|
Loading…
Reference in New Issue
Block a user