mirror of https://github.com/boa-dev/boa.git
Haled Odat
2 years ago
committed by
GitHub
37 changed files with 620 additions and 214 deletions
@ -0,0 +1,35 @@
|
||||
use boa_engine::{ |
||||
object::{FunctionObjectBuilder, ObjectInitializer}, |
||||
property::Attribute, |
||||
Context, JsArgs, JsObject, JsResult, JsValue, NativeFunction, |
||||
}; |
||||
|
||||
fn get_loop(_: &JsValue, _: &[JsValue], context: &mut Context<'_>) -> JsResult<JsValue> { |
||||
let max = context.runtime_limits().loop_iteration_limit(); |
||||
Ok(JsValue::from(max)) |
||||
} |
||||
|
||||
fn set_loop(_: &JsValue, args: &[JsValue], context: &mut Context<'_>) -> JsResult<JsValue> { |
||||
let value = args.get_or_undefined(0).to_length(context)?; |
||||
context.runtime_limits_mut().set_loop_iteration_limit(value); |
||||
Ok(JsValue::undefined()) |
||||
} |
||||
|
||||
pub(super) fn create_object(context: &mut Context<'_>) -> JsObject { |
||||
let get_loop = FunctionObjectBuilder::new(context, NativeFunction::from_fn_ptr(get_loop)) |
||||
.name("get loop") |
||||
.length(0) |
||||
.build(); |
||||
let set_loop = FunctionObjectBuilder::new(context, NativeFunction::from_fn_ptr(set_loop)) |
||||
.name("set loop") |
||||
.length(1) |
||||
.build(); |
||||
ObjectInitializer::new(context) |
||||
.accessor( |
||||
"loop", |
||||
Some(get_loop), |
||||
Some(set_loop), |
||||
Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, |
||||
) |
||||
.build() |
||||
} |
@ -0,0 +1,61 @@
|
||||
/// Represents the limits of different runtime operations.
|
||||
#[derive(Debug, Clone, Copy)] |
||||
pub struct RuntimeLimits { |
||||
/// Max stack size before an error is thrown.
|
||||
stack_size_limit: usize, |
||||
|
||||
/// Max loop iterations before an error is thrown.
|
||||
loop_iteration_limit: u64, |
||||
} |
||||
|
||||
impl Default for RuntimeLimits { |
||||
#[inline] |
||||
fn default() -> Self { |
||||
Self { |
||||
loop_iteration_limit: u64::MAX, |
||||
stack_size_limit: 1024, |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl RuntimeLimits { |
||||
/// Return the loop iteration limit.
|
||||
///
|
||||
/// If the limit is exceeded in a loop it will throw and errror.
|
||||
///
|
||||
/// The limit value [`u64::MAX`] means that there is no limit.
|
||||
#[inline] |
||||
#[must_use] |
||||
pub const fn loop_iteration_limit(&self) -> u64 { |
||||
self.loop_iteration_limit |
||||
} |
||||
|
||||
/// Set the loop iteration limit.
|
||||
///
|
||||
/// If the limit is exceeded in a loop it will throw and errror.
|
||||
///
|
||||
/// Setting the limit to [`u64::MAX`] means that there is no limit.
|
||||
#[inline] |
||||
pub fn set_loop_iteration_limit(&mut self, value: u64) { |
||||
self.loop_iteration_limit = value; |
||||
} |
||||
|
||||
/// Disable loop iteration limit.
|
||||
#[inline] |
||||
pub fn disable_loop_iteration_limit(&mut self) { |
||||
self.loop_iteration_limit = u64::MAX; |
||||
} |
||||
|
||||
/// Get max stack size.
|
||||
#[inline] |
||||
#[must_use] |
||||
pub const fn stack_size_limit(&self) -> usize { |
||||
self.stack_size_limit |
||||
} |
||||
|
||||
/// Set max stack size before an error is thrown.
|
||||
#[inline] |
||||
pub fn set_stack_size_limit(&mut self, value: usize) { |
||||
self.stack_size_limit = value; |
||||
} |
||||
} |
@ -0,0 +1,47 @@
|
||||
use boa_engine::{Context, Source}; |
||||
|
||||
fn main() { |
||||
// Create the JavaScript context.
|
||||
let mut context = Context::default(); |
||||
|
||||
// Set the context's runtime limit on loops to 10 iterations.
|
||||
context.runtime_limits_mut().set_loop_iteration_limit(10); |
||||
|
||||
// The code below iterates 5 times, so no error is thrown.
|
||||
let result = context.eval_script(Source::from_bytes( |
||||
r" |
||||
for (let i = 0; i < 5; ++i) { } |
||||
", |
||||
)); |
||||
result.expect("no error should be thrown"); |
||||
|
||||
// Here we exceed the limit by 1 iteration and a `RuntimeLimit` error is thrown.
|
||||
//
|
||||
// This error cannot be caught in JavaScript it propagates to rust caller.
|
||||
let result = context.eval_script(Source::from_bytes( |
||||
r" |
||||
try { |
||||
for (let i = 0; i < 11; ++i) { } |
||||
} catch (e) { |
||||
|
||||
} |
||||
", |
||||
)); |
||||
result.expect_err("should have throw an error"); |
||||
|
||||
// Preventing an infinity loops
|
||||
let result = context.eval_script(Source::from_bytes( |
||||
r" |
||||
while (true) { } |
||||
", |
||||
)); |
||||
result.expect_err("should have throw an error"); |
||||
|
||||
// The limit applies to all types of loops.
|
||||
let result = context.eval_script(Source::from_bytes( |
||||
r" |
||||
for (let e of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) { } |
||||
", |
||||
)); |
||||
result.expect_err("should have throw an error"); |
||||
} |
Loading…
Reference in new issue