Remove unnecessary unchecked gates.
This commit is contained in:
parent
80f95b6f2a
commit
42c0eeed57
@ -1,12 +1,31 @@
|
|||||||
//! Settings for [`Engine`]'s limitations.
|
//! Settings for [`Engine`]'s limitations.
|
||||||
#![cfg(not(feature = "unchecked"))]
|
#![cfg(not(feature = "unchecked"))]
|
||||||
|
|
||||||
use super::default_limits;
|
|
||||||
use crate::Engine;
|
use crate::Engine;
|
||||||
use std::num::{NonZeroU64, NonZeroUsize};
|
use std::num::{NonZeroU64, NonZeroUsize};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
|
pub mod default_limits {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
pub const MAX_CALL_STACK_DEPTH: usize = 8;
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub const MAX_EXPR_DEPTH: usize = 32;
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16;
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
pub const MAX_CALL_STACK_DEPTH: usize = 64;
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
pub const MAX_EXPR_DEPTH: usize = 64;
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
|
||||||
|
}
|
||||||
|
|
||||||
/// A type containing all the limits imposed by the [`Engine`].
|
/// A type containing all the limits imposed by the [`Engine`].
|
||||||
///
|
///
|
||||||
/// Not available under `unchecked`.
|
/// Not available under `unchecked`.
|
||||||
|
@ -43,28 +43,7 @@ use std::prelude::v1::*;
|
|||||||
|
|
||||||
pub mod default_limits {
|
pub mod default_limits {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(debug_assertions)]
|
pub use super::limits::default_limits::*;
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
pub const MAX_CALL_STACK_DEPTH: usize = 8;
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
pub const MAX_EXPR_DEPTH: usize = 32;
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
pub const MAX_CALL_STACK_DEPTH: usize = 64;
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
pub const MAX_EXPR_DEPTH: usize = 64;
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
|
|
||||||
|
|
||||||
pub const MAX_DYNAMIC_PARAMETERS: usize = 16;
|
pub const MAX_DYNAMIC_PARAMETERS: usize = 16;
|
||||||
}
|
}
|
||||||
@ -236,55 +215,3 @@ impl Engine {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
|
||||||
impl Engine {
|
|
||||||
/// The maximum levels of function calls allowed for a script.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_call_levels(&self) -> usize {
|
|
||||||
usize::MAX
|
|
||||||
}
|
|
||||||
/// The maximum number of operations allowed for a script to run (0 for unlimited).
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_operations(&self) -> u64 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
/// The maximum number of imported [modules][crate::Module] allowed for a script.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_modules(&self) -> usize {
|
|
||||||
usize::MAX
|
|
||||||
}
|
|
||||||
/// The depth limit for expressions (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_expr_depth(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
/// The depth limit for expressions in functions (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_function_expr_depth(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
/// The maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_string_size(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
/// The maximum length of [arrays][crate::Array] (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_array_size(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
/// The maximum size of [object maps][crate::Map] (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_map_size(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -347,9 +347,9 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check a result to ensure that it is valid.
|
/// Check a result to ensure that it is valid.
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn check_return_value(&self, result: RhaiResult, _pos: Position) -> RhaiResult {
|
pub(crate) fn check_return_value(&self, result: RhaiResult, _pos: Position) -> RhaiResult {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if let Ok(ref r) = result {
|
if let Ok(ref r) = result {
|
||||||
self.check_data_size(r, _pos)?;
|
self.check_data_size(r, _pos)?;
|
||||||
}
|
}
|
||||||
@ -357,3 +357,81 @@ impl Engine {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "unchecked")]
|
||||||
|
impl Engine {
|
||||||
|
/// The maximum levels of function calls allowed for a script.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_call_levels(&self) -> usize {
|
||||||
|
usize::MAX
|
||||||
|
}
|
||||||
|
/// The maximum number of operations allowed for a script to run (0 for unlimited).
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_operations(&self) -> u64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
/// The maximum number of imported [modules][crate::Module] allowed for a script.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_modules(&self) -> usize {
|
||||||
|
usize::MAX
|
||||||
|
}
|
||||||
|
/// The depth limit for expressions (0 for unlimited).
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_expr_depth(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
/// The depth limit for expressions in functions (0 for unlimited).
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_function_expr_depth(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
/// The maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_string_size(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
/// The maximum length of [arrays][crate::Array] (0 for unlimited).
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_array_size(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
/// The maximum size of [object maps][crate::Map] (0 for unlimited).
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_map_size(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the number of operations stay within limit.
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) const fn track_operation(
|
||||||
|
&self,
|
||||||
|
_: &crate::GlobalRuntimeState,
|
||||||
|
_: Position,
|
||||||
|
) -> crate::RhaiResultOf<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check whether the size of a [`Dynamic`] is within limits.
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) const fn check_data_size(
|
||||||
|
&self,
|
||||||
|
_: &Dynamic,
|
||||||
|
_: Position,
|
||||||
|
) -> crate::RhaiResultOf<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check a result to ensure that it is valid.
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) const fn check_return_value(&self, result: RhaiResult, _: Position) -> RhaiResult {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -131,7 +131,6 @@ impl Engine {
|
|||||||
self.eval_op_assignment(
|
self.eval_op_assignment(
|
||||||
global, caches, lib, op_info, obj_ptr, root, new_val, level,
|
global, caches, lib, op_info, obj_ptr, root, new_val, level,
|
||||||
)?;
|
)?;
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
self.check_data_size(obj_ptr, op_info.pos)?;
|
self.check_data_size(obj_ptr, op_info.pos)?;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -159,7 +158,6 @@ impl Engine {
|
|||||||
)?;
|
)?;
|
||||||
// Replace new value
|
// Replace new value
|
||||||
new_val = val.take_or_clone();
|
new_val = val.take_or_clone();
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
self.check_data_size(&new_val, op_info.pos)?;
|
self.check_data_size(&new_val, op_info.pos)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,7 +244,6 @@ impl Engine {
|
|||||||
global, caches, lib, op_info, val_target, root, new_val, level,
|
global, caches, lib, op_info, val_target, root, new_val, level,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
self.check_data_size(target.source(), op_info.pos)?;
|
self.check_data_size(target.source(), op_info.pos)?;
|
||||||
Ok((Dynamic::UNIT, true))
|
Ok((Dynamic::UNIT, true))
|
||||||
}
|
}
|
||||||
@ -606,9 +603,7 @@ impl Engine {
|
|||||||
Expr::Variable(x, .., var_pos) => {
|
Expr::Variable(x, .., var_pos) => {
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
self.run_debugger(scope, global, lib, this_ptr, lhs, level)?;
|
self.run_debugger(scope, global, lib, this_ptr, lhs, level)?;
|
||||||
|
self.track_operation(global, *var_pos)?;
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
self.inc_operations(&mut global.num_operations, *var_pos)?;
|
|
||||||
|
|
||||||
let (mut target, ..) =
|
let (mut target, ..) =
|
||||||
self.search_namespace(scope, global, lib, this_ptr, lhs, level)?;
|
self.search_namespace(scope, global, lib, this_ptr, lhs, level)?;
|
||||||
@ -655,8 +650,7 @@ impl Engine {
|
|||||||
idx_values: &mut FnArgsVec<Dynamic>,
|
idx_values: &mut FnArgsVec<Dynamic>,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResultOf<()> {
|
) -> RhaiResultOf<()> {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, expr.position())?;
|
||||||
self.inc_operations(&mut global.num_operations, expr.position())?;
|
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -814,8 +808,7 @@ impl Engine {
|
|||||||
use_indexers: bool,
|
use_indexers: bool,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResultOf<Target<'t>> {
|
) -> RhaiResultOf<Target<'t>> {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, Position::NONE)?;
|
||||||
self.inc_operations(&mut global.num_operations, Position::NONE)?;
|
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Data size checks during evaluation.
|
//! Data size checks during evaluation.
|
||||||
#![cfg(not(feature = "unchecked"))]
|
#![cfg(not(feature = "unchecked"))]
|
||||||
|
|
||||||
|
use super::GlobalRuntimeState;
|
||||||
use crate::types::dynamic::Union;
|
use crate::types::dynamic::Union;
|
||||||
use crate::{Dynamic, Engine, Position, RhaiResultOf, ERR};
|
use crate::{Dynamic, Engine, Position, RhaiResultOf, ERR};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
@ -15,7 +16,6 @@ impl Engine {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if any interior data is shared (should never happen).
|
/// Panics if any interior data is shared (should never happen).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
pub(crate) fn calc_data_sizes(value: &Dynamic, _top: bool) -> (usize, usize, usize) {
|
pub(crate) fn calc_data_sizes(value: &Dynamic, _top: bool) -> (usize, usize, usize) {
|
||||||
match value.0 {
|
match value.0 {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -71,24 +71,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Is there a data size limit set?
|
/// Is there a data size limit set?
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
pub(crate) const fn has_data_size_limit(&self) -> bool {
|
pub(crate) const fn has_data_size_limit(&self) -> bool {
|
||||||
let mut _limited = self.limits.max_string_size.is_some();
|
self.max_string_size() > 0 || self.max_array_size() > 0 || self.max_map_size() > 0
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
{
|
|
||||||
_limited = _limited || self.limits.max_array_size.is_some();
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
{
|
|
||||||
_limited = _limited || self.limits.max_map_size.is_some();
|
|
||||||
}
|
|
||||||
|
|
||||||
_limited
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raise an error if any data size exceeds limit.
|
/// Raise an error if any data size exceeds limit.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
pub(crate) fn raise_err_if_over_data_size_limit(
|
pub(crate) fn raise_err_if_over_data_size_limit(
|
||||||
&self,
|
&self,
|
||||||
sizes: (usize, usize, usize),
|
sizes: (usize, usize, usize),
|
||||||
@ -128,7 +115,6 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether the size of a [`Dynamic`] is within limits.
|
/// Check whether the size of a [`Dynamic`] is within limits.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
pub(crate) fn check_data_size(&self, value: &Dynamic, pos: Position) -> RhaiResultOf<()> {
|
pub(crate) fn check_data_size(&self, value: &Dynamic, pos: Position) -> RhaiResultOf<()> {
|
||||||
// If no data size limits, just return
|
// If no data size limits, just return
|
||||||
if !self.has_data_size_limit() {
|
if !self.has_data_size_limit() {
|
||||||
@ -143,29 +129,30 @@ impl Engine {
|
|||||||
/// Raise an error if the size of a [`Dynamic`] is out of limits (if any).
|
/// Raise an error if the size of a [`Dynamic`] is out of limits (if any).
|
||||||
///
|
///
|
||||||
/// Not available under `unchecked`.
|
/// Not available under `unchecked`.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn ensure_data_size_within_limits(&self, value: &Dynamic) -> RhaiResultOf<()> {
|
pub fn ensure_data_size_within_limits(&self, value: &Dynamic) -> RhaiResultOf<()> {
|
||||||
self.check_data_size(value, Position::NONE)
|
self.check_data_size(value, Position::NONE)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the number of operations stay within limit.
|
/// Check if the number of operations stay within limit.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
pub(crate) fn track_operation(
|
||||||
pub(crate) fn inc_operations(
|
|
||||||
&self,
|
&self,
|
||||||
num_operations: &mut u64,
|
global: &mut GlobalRuntimeState,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> RhaiResultOf<()> {
|
) -> RhaiResultOf<()> {
|
||||||
*num_operations += 1;
|
global.num_operations += 1;
|
||||||
|
|
||||||
// Guard against too many operations
|
// Guard against too many operations
|
||||||
if self.max_operations() > 0 && *num_operations > self.max_operations() {
|
let max = self.max_operations();
|
||||||
|
let num_operations = global.num_operations;
|
||||||
|
|
||||||
|
if max > 0 && num_operations > max {
|
||||||
return Err(ERR::ErrorTooManyOperations(pos).into());
|
return Err(ERR::ErrorTooManyOperations(pos).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report progress - only in steps
|
// Report progress - only in steps
|
||||||
if let Some(ref progress) = self.progress {
|
if let Some(ref progress) = self.progress {
|
||||||
if let Some(token) = progress(*num_operations) {
|
if let Some(token) = progress(num_operations) {
|
||||||
// Terminate script if progress returns a termination token
|
// Terminate script if progress returns a termination token
|
||||||
return Err(ERR::ErrorTerminated(token, pos).into());
|
return Err(ERR::ErrorTerminated(token, pos).into());
|
||||||
}
|
}
|
||||||
|
@ -318,8 +318,7 @@ impl Engine {
|
|||||||
let reset_debugger =
|
let reset_debugger =
|
||||||
self.run_debugger_with_reset(scope, global, lib, this_ptr, expr, level)?;
|
self.run_debugger_with_reset(scope, global, lib, this_ptr, expr, level)?;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, expr.position())?;
|
||||||
self.inc_operations(&mut global.num_operations, expr.position())?;
|
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
self.eval_fn_call_expr(scope, global, caches, lib, this_ptr, x, x.pos, level);
|
self.eval_fn_call_expr(scope, global, caches, lib, this_ptr, x, x.pos, level);
|
||||||
@ -337,8 +336,7 @@ impl Engine {
|
|||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
self.run_debugger(scope, global, lib, this_ptr, expr, level)?;
|
self.run_debugger(scope, global, lib, this_ptr, expr, level)?;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, expr.position())?;
|
||||||
self.inc_operations(&mut global.num_operations, expr.position())?;
|
|
||||||
|
|
||||||
return if index.is_none() && x.0.is_none() && x.3 == KEYWORD_THIS {
|
return if index.is_none() && x.0.is_none() && x.3 == KEYWORD_THIS {
|
||||||
this_ptr
|
this_ptr
|
||||||
@ -355,8 +353,7 @@ impl Engine {
|
|||||||
let reset_debugger =
|
let reset_debugger =
|
||||||
self.run_debugger_with_reset(scope, global, lib, this_ptr, expr, level)?;
|
self.run_debugger_with_reset(scope, global, lib, this_ptr, expr, level)?;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, expr.position())?;
|
||||||
self.inc_operations(&mut global.num_operations, expr.position())?;
|
|
||||||
|
|
||||||
let result = match expr {
|
let result = match expr {
|
||||||
// Constants
|
// Constants
|
||||||
@ -410,7 +407,7 @@ impl Engine {
|
|||||||
let mut result = Ok(Dynamic::UNIT);
|
let mut result = Ok(Dynamic::UNIT);
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
let mut sizes = (0, 0, 0);
|
let mut total_data_sizes = (0, 0, 0);
|
||||||
|
|
||||||
for item_expr in &**x {
|
for item_expr in &**x {
|
||||||
let value = match self
|
let value = match self
|
||||||
@ -424,19 +421,21 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
let val_sizes = Self::calc_data_sizes(&value, true);
|
if self.has_data_size_limit() {
|
||||||
|
let val_sizes = Self::calc_data_sizes(&value, true);
|
||||||
|
|
||||||
|
total_data_sizes = (
|
||||||
|
total_data_sizes.0 + val_sizes.0,
|
||||||
|
total_data_sizes.1 + val_sizes.1,
|
||||||
|
total_data_sizes.2 + val_sizes.2,
|
||||||
|
);
|
||||||
|
self.raise_err_if_over_data_size_limit(
|
||||||
|
total_data_sizes,
|
||||||
|
item_expr.position(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
array.push(value);
|
array.push(value);
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if self.has_data_size_limit() {
|
|
||||||
sizes = (
|
|
||||||
sizes.0 + val_sizes.0,
|
|
||||||
sizes.1 + val_sizes.1,
|
|
||||||
sizes.2 + val_sizes.2,
|
|
||||||
);
|
|
||||||
self.raise_err_if_over_data_size_limit(sizes, item_expr.position())?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.map(|_| array.into())
|
result.map(|_| array.into())
|
||||||
@ -448,7 +447,7 @@ impl Engine {
|
|||||||
let mut result = Ok(Dynamic::UNIT);
|
let mut result = Ok(Dynamic::UNIT);
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
let mut sizes = (0, 0, 0);
|
let mut total_data_sizes = (0, 0, 0);
|
||||||
|
|
||||||
for (key, value_expr) in &x.0 {
|
for (key, value_expr) in &x.0 {
|
||||||
let value = match self
|
let value = match self
|
||||||
@ -462,15 +461,20 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
let delta = Self::calc_data_sizes(&value, true);
|
if self.has_data_size_limit() {
|
||||||
|
let delta = Self::calc_data_sizes(&value, true);
|
||||||
|
total_data_sizes = (
|
||||||
|
total_data_sizes.0 + delta.0,
|
||||||
|
total_data_sizes.1 + delta.1,
|
||||||
|
total_data_sizes.2 + delta.2,
|
||||||
|
);
|
||||||
|
self.raise_err_if_over_data_size_limit(
|
||||||
|
total_data_sizes,
|
||||||
|
value_expr.position(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
*map.get_mut(key.as_str()).unwrap() = value;
|
*map.get_mut(key.as_str()).unwrap() = value;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if self.has_data_size_limit() {
|
|
||||||
sizes = (sizes.0 + delta.0, sizes.1 + delta.1, sizes.2 + delta.2);
|
|
||||||
self.raise_err_if_over_data_size_limit(sizes, value_expr.position())?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.map(|_| map.into())
|
result.map(|_| map.into())
|
||||||
|
@ -152,7 +152,6 @@ impl Engine {
|
|||||||
let context = (self, op, None, &*global, lib, *op_pos, level).into();
|
let context = (self, op, None, &*global, lib, *op_pos, level).into();
|
||||||
let result = func(context, args).map(|_| ());
|
let result = func(context, args).map(|_| ());
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
self.check_data_size(args[0], root.1)?;
|
self.check_data_size(args[0], root.1)?;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -165,10 +164,7 @@ impl Engine {
|
|||||||
match self.call_native_fn(
|
match self.call_native_fn(
|
||||||
global, caches, lib, op_assign, hash, args, true, true, *op_pos, level,
|
global, caches, lib, op_assign, hash, args, true, true, *op_pos, level,
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => self.check_data_size(args[0], root.1)?,
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
self.check_data_size(args[0], root.1)?;
|
|
||||||
}
|
|
||||||
Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_assign)) =>
|
Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_assign)) =>
|
||||||
{
|
{
|
||||||
// Expand to `var = var op rhs`
|
// Expand to `var = var op rhs`
|
||||||
@ -218,8 +214,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Function calls should account for a relatively larger portion of statements.
|
// Function calls should account for a relatively larger portion of statements.
|
||||||
if let Stmt::FnCall(x, ..) = stmt {
|
if let Stmt::FnCall(x, ..) = stmt {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, stmt.position())?;
|
||||||
self.inc_operations(&mut global.num_operations, stmt.position())?;
|
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
self.eval_fn_call_expr(scope, global, caches, lib, this_ptr, x, x.pos, level);
|
self.eval_fn_call_expr(scope, global, caches, lib, this_ptr, x, x.pos, level);
|
||||||
@ -236,8 +231,7 @@ impl Engine {
|
|||||||
if let Stmt::Assignment(x, ..) = stmt {
|
if let Stmt::Assignment(x, ..) = stmt {
|
||||||
let (op_info, BinaryExpr { lhs, rhs }) = &**x;
|
let (op_info, BinaryExpr { lhs, rhs }) = &**x;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, stmt.position())?;
|
||||||
self.inc_operations(&mut global.num_operations, stmt.position())?;
|
|
||||||
|
|
||||||
let result = if let Expr::Variable(x, ..) = lhs {
|
let result = if let Expr::Variable(x, ..) = lhs {
|
||||||
let rhs_result = self
|
let rhs_result = self
|
||||||
@ -267,8 +261,7 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, pos)?;
|
||||||
self.inc_operations(&mut global.num_operations, pos)?;
|
|
||||||
|
|
||||||
let root = (var_name, pos);
|
let root = (var_name, pos);
|
||||||
let lhs_ptr = &mut lhs_ptr;
|
let lhs_ptr = &mut lhs_ptr;
|
||||||
@ -339,8 +332,7 @@ impl Engine {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, stmt.position())?;
|
||||||
self.inc_operations(&mut global.num_operations, stmt.position())?;
|
|
||||||
|
|
||||||
let result = match stmt {
|
let result = match stmt {
|
||||||
// No-op
|
// No-op
|
||||||
@ -512,8 +504,7 @@ impl Engine {
|
|||||||
let (.., body) = &**x;
|
let (.., body) = &**x;
|
||||||
|
|
||||||
if body.is_empty() {
|
if body.is_empty() {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, body.position())?;
|
||||||
self.inc_operations(&mut global.num_operations, body.position())?;
|
|
||||||
} else {
|
} else {
|
||||||
match self
|
match self
|
||||||
.eval_stmt_block(scope, global, caches, lib, this_ptr, body, true, level)
|
.eval_stmt_block(scope, global, caches, lib, this_ptr, body, true, level)
|
||||||
@ -668,10 +659,7 @@ impl Engine {
|
|||||||
|
|
||||||
*scope.get_mut_by_index(index).write_lock().unwrap() = value;
|
*scope.get_mut_by_index(index).write_lock().unwrap() = value;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
if let Err(err) = self.track_operation(global, statements.position()) {
|
||||||
if let Err(err) = self
|
|
||||||
.inc_operations(&mut global.num_operations, statements.position())
|
|
||||||
{
|
|
||||||
loop_result = Err(err);
|
loop_result = Err(err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,7 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
($x:ty, $xx:ident, $y:ty, $yy:ident) => {
|
($x:ty, $xx:ident, $y:ty, $yy:ident) => {
|
||||||
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
use crate::packages::arithmetic::decimal_functions::*;
|
use crate::packages::arithmetic::decimal_functions::builtin::*;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
match op {
|
match op {
|
||||||
@ -697,7 +697,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
($x:ident, $xx:ident, $y:ty, $yy:ident) => {
|
($x:ident, $xx:ident, $y:ty, $yy:ident) => {
|
||||||
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
use crate::packages::arithmetic::decimal_functions::*;
|
use crate::packages::arithmetic::decimal_functions::builtin::*;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
return match op {
|
return match op {
|
||||||
|
@ -358,8 +358,7 @@ impl Engine {
|
|||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResultOf<(Dynamic, bool)> {
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, pos)?;
|
||||||
self.inc_operations(&mut global.num_operations, pos)?;
|
|
||||||
|
|
||||||
let parent_source = global.source.clone();
|
let parent_source = global.source.clone();
|
||||||
let op_assign = if is_op_assign {
|
let op_assign = if is_op_assign {
|
||||||
@ -1232,8 +1231,7 @@ impl Engine {
|
|||||||
target = target.into_owned();
|
target = target.into_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, _pos)?;
|
||||||
self.inc_operations(&mut global.num_operations, _pos)?;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
let target_is_shared = target.is_shared();
|
let target_is_shared = target.is_shared();
|
||||||
@ -1312,8 +1310,7 @@ impl Engine {
|
|||||||
let (target, _pos) =
|
let (target, _pos) =
|
||||||
self.search_scope_only(scope, global, lib, this_ptr, first_arg, level)?;
|
self.search_scope_only(scope, global, lib, this_ptr, first_arg, level)?;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, _pos)?;
|
||||||
self.inc_operations(&mut global.num_operations, _pos)?;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
let target_is_shared = target.is_shared();
|
let target_is_shared = target.is_shared();
|
||||||
@ -1350,9 +1347,7 @@ impl Engine {
|
|||||||
let mut func = match module.get_qualified_fn(hash) {
|
let mut func = match module.get_qualified_fn(hash) {
|
||||||
// Then search native Rust functions
|
// Then search native Rust functions
|
||||||
None => {
|
None => {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, pos)?;
|
||||||
self.inc_operations(&mut global.num_operations, pos)?;
|
|
||||||
|
|
||||||
let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id()));
|
let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id()));
|
||||||
let hash_qualified_fn = combine_hashes(hash, hash_params);
|
let hash_qualified_fn = combine_hashes(hash, hash_params);
|
||||||
|
|
||||||
@ -1384,8 +1379,7 @@ impl Engine {
|
|||||||
}));
|
}));
|
||||||
let hash_qualified_fn = combine_hashes(hash, hash_params);
|
let hash_qualified_fn = combine_hashes(hash, hash_params);
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, pos)?;
|
||||||
self.inc_operations(&mut global.num_operations, pos)?;
|
|
||||||
|
|
||||||
if let Some(f) = module.get_qualified_fn(hash_qualified_fn) {
|
if let Some(f) = module.get_qualified_fn(hash_qualified_fn) {
|
||||||
func = Some(f);
|
func = Some(f);
|
||||||
@ -1461,8 +1455,7 @@ impl Engine {
|
|||||||
_pos: Position,
|
_pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, _pos)?;
|
||||||
self.inc_operations(&mut global.num_operations, _pos)?;
|
|
||||||
|
|
||||||
let script = script.trim();
|
let script = script.trim();
|
||||||
|
|
||||||
|
@ -63,8 +63,7 @@ impl Engine {
|
|||||||
|
|
||||||
assert!(fn_def.params.len() == args.len());
|
assert!(fn_def.params.len() == args.len());
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
self.track_operation(global, pos)?;
|
||||||
self.inc_operations(&mut global.num_operations, pos)?;
|
|
||||||
|
|
||||||
// Check for stack overflow
|
// Check for stack overflow
|
||||||
if level > self.max_call_levels() {
|
if level > self.max_call_levels() {
|
||||||
|
@ -488,39 +488,29 @@ mod f64_functions {
|
|||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
pub mod decimal_functions {
|
pub mod decimal_functions {
|
||||||
use num_traits::Pow;
|
use rust_decimal::{prelude::Zero, Decimal};
|
||||||
use rust_decimal::{prelude::Zero, Decimal, MathematicalOps};
|
|
||||||
|
|
||||||
#[rhai_fn(skip, return_raw)]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn add(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
pub mod builtin {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
use rust_decimal::MathematicalOps;
|
||||||
|
|
||||||
|
#[rhai_fn(return_raw)]
|
||||||
|
pub fn add(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
||||||
x.checked_add(y)
|
x.checked_add(y)
|
||||||
.ok_or_else(|| make_err(format!("Addition overflow: {x} + {y}")))
|
.ok_or_else(|| make_err(format!("Addition overflow: {x} + {y}")))
|
||||||
} else {
|
|
||||||
Ok(x + y)
|
|
||||||
}
|
}
|
||||||
}
|
#[rhai_fn(return_raw)]
|
||||||
#[rhai_fn(skip, return_raw)]
|
pub fn subtract(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
||||||
pub fn subtract(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
|
||||||
if cfg!(not(feature = "unchecked")) {
|
|
||||||
x.checked_sub(y)
|
x.checked_sub(y)
|
||||||
.ok_or_else(|| make_err(format!("Subtraction overflow: {x} - {y}")))
|
.ok_or_else(|| make_err(format!("Subtraction overflow: {x} - {y}")))
|
||||||
} else {
|
|
||||||
Ok(x - y)
|
|
||||||
}
|
}
|
||||||
}
|
#[rhai_fn(return_raw)]
|
||||||
#[rhai_fn(skip, return_raw)]
|
pub fn multiply(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
||||||
pub fn multiply(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
|
||||||
if cfg!(not(feature = "unchecked")) {
|
|
||||||
x.checked_mul(y)
|
x.checked_mul(y)
|
||||||
.ok_or_else(|| make_err(format!("Multiplication overflow: {x} * {y}")))
|
.ok_or_else(|| make_err(format!("Multiplication overflow: {x} * {y}")))
|
||||||
} else {
|
|
||||||
Ok(x * y)
|
|
||||||
}
|
}
|
||||||
}
|
#[rhai_fn(return_raw)]
|
||||||
#[rhai_fn(skip, return_raw)]
|
pub fn divide(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
||||||
pub fn divide(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
|
||||||
if cfg!(not(feature = "unchecked")) {
|
|
||||||
// Detect division by zero
|
// Detect division by zero
|
||||||
if y == Decimal::zero() {
|
if y == Decimal::zero() {
|
||||||
Err(make_err(format!("Division by zero: {x} / {y}")))
|
Err(make_err(format!("Division by zero: {x} / {y}")))
|
||||||
@ -528,26 +518,16 @@ pub mod decimal_functions {
|
|||||||
x.checked_div(y)
|
x.checked_div(y)
|
||||||
.ok_or_else(|| make_err(format!("Division overflow: {x} / {y}")))
|
.ok_or_else(|| make_err(format!("Division overflow: {x} / {y}")))
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Ok(x / y)
|
|
||||||
}
|
}
|
||||||
}
|
#[rhai_fn(return_raw)]
|
||||||
#[rhai_fn(skip, return_raw)]
|
pub fn modulo(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
||||||
pub fn modulo(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
|
||||||
if cfg!(not(feature = "unchecked")) {
|
|
||||||
x.checked_rem(y)
|
x.checked_rem(y)
|
||||||
.ok_or_else(|| make_err(format!("Modulo division by zero or overflow: {x} % {y}")))
|
.ok_or_else(|| make_err(format!("Modulo division by zero or overflow: {x} % {y}")))
|
||||||
} else {
|
|
||||||
Ok(x % y)
|
|
||||||
}
|
}
|
||||||
}
|
#[rhai_fn(return_raw)]
|
||||||
#[rhai_fn(skip, return_raw)]
|
pub fn power(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
||||||
pub fn power(x: Decimal, y: Decimal) -> RhaiResultOf<Decimal> {
|
|
||||||
if cfg!(not(feature = "unchecked")) {
|
|
||||||
x.checked_powd(y)
|
x.checked_powd(y)
|
||||||
.ok_or_else(|| make_err(format!("Exponential overflow: {x} ** {y}")))
|
.ok_or_else(|| make_err(format!("Exponential overflow: {x} ** {y}")))
|
||||||
} else {
|
|
||||||
Ok(x.pow(y))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "-")]
|
#[rhai_fn(name = "-")]
|
||||||
|
@ -236,9 +236,8 @@ pub mod array_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let check_sizes = match item.0 {
|
let check_sizes = match item.0 {
|
||||||
crate::types::dynamic::Union::Array(..) | crate::types::dynamic::Union::Str(..) => {
|
crate::types::dynamic::Union::Str(..) => true,
|
||||||
true
|
crate::types::dynamic::Union::Array(..) => true,
|
||||||
}
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
crate::types::dynamic::Union::Map(..) => true,
|
crate::types::dynamic::Union::Map(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
Loading…
Reference in New Issue
Block a user