Fix unsafe violation in for loop.
This commit is contained in:
parent
2677e7dc8a
commit
a8ec984b0f
@ -11,6 +11,7 @@ Bug fixes
|
|||||||
* `chop` for arrays and BLOB's now works properly.
|
* `chop` for arrays and BLOB's now works properly.
|
||||||
* `set_bit` for bit-flags with negative index now works correctly.
|
* `set_bit` for bit-flags with negative index now works correctly.
|
||||||
* Misnamed `params` field `name` in the JSON output of `Engine::gen_fn_metadata_to_json` is fixed (was incorrectly named `type`).
|
* Misnamed `params` field `name` in the JSON output of `Engine::gen_fn_metadata_to_json` is fixed (was incorrectly named `type`).
|
||||||
|
* Fixes a potential `unsafe` violation in `for` loop.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
@ -464,7 +464,7 @@ impl Engine {
|
|||||||
|
|
||||||
// For loop
|
// For loop
|
||||||
Stmt::For(expr, x, _) => {
|
Stmt::For(expr, x, _) => {
|
||||||
let (Ident { name, .. }, counter, statements) = x.as_ref();
|
let (Ident { name: var_name, .. }, counter, statements) = x.as_ref();
|
||||||
let iter_obj = self
|
let iter_obj = self
|
||||||
.eval_expr(scope, global, state, lib, this_ptr, expr, level)?
|
.eval_expr(scope, global, state, lib, this_ptr, expr, level)?
|
||||||
.flatten();
|
.flatten();
|
||||||
@ -492,14 +492,23 @@ impl Engine {
|
|||||||
// Add the loop variables
|
// Add the loop variables
|
||||||
let orig_scope_len = scope.len();
|
let orig_scope_len = scope.len();
|
||||||
let counter_index = if let Some(counter) = counter {
|
let counter_index = if let Some(counter) = counter {
|
||||||
scope.push(unsafe_cast_var_name_to_lifetime(&counter.name), 0 as INT);
|
// Loop variables are always removed at the end of the statement
|
||||||
|
// so this cast is safe.
|
||||||
|
let counter_name = unsafe_cast_var_name_to_lifetime(&counter.name);
|
||||||
|
scope.push(counter_name, 0 as INT);
|
||||||
scope.len() - 1
|
scope.len() - 1
|
||||||
} else {
|
} else {
|
||||||
usize::MAX
|
usize::MAX
|
||||||
};
|
};
|
||||||
scope.push(unsafe_cast_var_name_to_lifetime(name), ());
|
|
||||||
|
// Loop variables are always removed at the end of the statement
|
||||||
|
// so this cast is safe.
|
||||||
|
let var_name = unsafe_cast_var_name_to_lifetime(var_name);
|
||||||
|
scope.push(var_name, ());
|
||||||
let index = scope.len() - 1;
|
let index = scope.len() - 1;
|
||||||
|
|
||||||
|
let mut loop_result = Ok(Dynamic::UNIT);
|
||||||
|
|
||||||
for (x, iter_value) in func(iter_obj).enumerate() {
|
for (x, iter_value) in func(iter_obj).enumerate() {
|
||||||
// Increment counter
|
// Increment counter
|
||||||
if counter_index < usize::MAX {
|
if counter_index < usize::MAX {
|
||||||
@ -546,7 +555,12 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(&mut global.num_operations, statements.position())?;
|
if let Err(err) =
|
||||||
|
self.inc_operations(&mut global.num_operations, statements.position())
|
||||||
|
{
|
||||||
|
loop_result = Err(err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if statements.is_empty() {
|
if statements.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
@ -567,7 +581,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scope.rewind(orig_scope_len);
|
scope.rewind(orig_scope_len);
|
||||||
Ok(Dynamic::UNIT)
|
|
||||||
|
loop_result
|
||||||
} else {
|
} else {
|
||||||
Err(ERR::ErrorFor(expr.position()).into())
|
Err(ERR::ErrorFor(expr.position()).into())
|
||||||
}
|
}
|
||||||
@ -580,7 +595,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Try/Catch statement
|
// Try/Catch statement
|
||||||
Stmt::TryCatch(x, _) => {
|
Stmt::TryCatch(x, _) => {
|
||||||
let (try_stmt, err_var, catch_stmt) = x.as_ref();
|
let (try_stmt, err_var_name, catch_stmt) = x.as_ref();
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.eval_stmt_block(scope, global, state, lib, this_ptr, try_stmt, true, level)
|
.eval_stmt_block(scope, global, state, lib, this_ptr, try_stmt, true, level)
|
||||||
@ -630,8 +645,11 @@ impl Engine {
|
|||||||
|
|
||||||
let orig_scope_len = scope.len();
|
let orig_scope_len = scope.len();
|
||||||
|
|
||||||
err_var.as_ref().map(|Ident { name, .. }| {
|
err_var_name.as_ref().map(|Ident { name, .. }| {
|
||||||
scope.push(unsafe_cast_var_name_to_lifetime(name), err_value)
|
// Catch error variables are always removed from after the block
|
||||||
|
// so this cast is safe.
|
||||||
|
let var_name = unsafe_cast_var_name_to_lifetime(name);
|
||||||
|
scope.push(var_name, err_value)
|
||||||
});
|
});
|
||||||
|
|
||||||
let result = self.eval_stmt_block(
|
let result = self.eval_stmt_block(
|
||||||
|
@ -74,14 +74,18 @@ impl Engine {
|
|||||||
let orig_mods_len = global.num_imported_modules();
|
let orig_mods_len = global.num_imported_modules();
|
||||||
|
|
||||||
// Put arguments into scope as variables
|
// Put arguments into scope as variables
|
||||||
// Actually consume the arguments instead of cloning them
|
|
||||||
scope.extend(
|
scope.extend(
|
||||||
fn_def
|
fn_def
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.zip(args.iter_mut().map(|v| mem::take(*v)))
|
.zip(args.into_iter().map(|v| {
|
||||||
|
// Actually consume the arguments instead of cloning them
|
||||||
|
mem::take(*v)
|
||||||
|
}))
|
||||||
.map(|(name, value)| {
|
.map(|(name, value)| {
|
||||||
let var_name: std::borrow::Cow<'_, str> =
|
// Arguments are always removed at the end of the call,
|
||||||
|
// so this cast is safe.
|
||||||
|
let var_name: std::borrow::Cow<_> =
|
||||||
unsafe_cast_var_name_to_lifetime(name).into();
|
unsafe_cast_var_name_to_lifetime(name).into();
|
||||||
(var_name, value)
|
(var_name, value)
|
||||||
}),
|
}),
|
||||||
|
Loading…
Reference in New Issue
Block a user