From 0724a7832b9a765e45c5d431df0f00b665d4ea94 Mon Sep 17 00:00:00 2001 From: Iban Eguia Date: Sun, 5 Dec 2021 00:41:59 +0000 Subject: [PATCH] Added fallible allocation to data blocks (#1728) This Pull Request uses the new fallible allocation API in Rust 1.57 to follow the JavaScript specification for data blocks: https://tc39.es/ecma262/#sec-createbytedatablock It changes the following: - Creating a new DataBlock for an ArrayBuffer will no longer fail with an arbitrary byte length, it will now actually call the allocator and try to reserve the needed space, and fail if it can't. - Added sunny and rainy day unit tests that check if the API works as expected. - Bumped the minimum Rust version to Rust 1.57 for the Boa crate. - Removed the unused `DataBlock` implementation in IntegerIndexedObjects. --- boa/Cargo.toml | 2 +- boa/src/builtins/array_buffer/mod.rs | 30 ++++++++++++--- boa/src/builtins/array_buffer/tests.rs | 15 ++++++++ .../typed_array/integer_indexed_object.rs | 37 +------------------ 4 files changed, 42 insertions(+), 42 deletions(-) create mode 100644 boa/src/builtins/array_buffer/tests.rs diff --git a/boa/Cargo.toml b/boa/Cargo.toml index 5b1aca6f3f..5a45eab54c 100644 --- a/boa/Cargo.toml +++ b/boa/Cargo.toml @@ -9,7 +9,7 @@ categories = ["parser-implementations", "wasm"] license = "Unlicense/MIT" exclude = ["../.vscode/*", "../Dockerfile", "../Makefile", "../.editorConfig"] edition = "2021" -rust-version = "1.56" +rust-version = "1.57" [features] profiler = ["measureme"] diff --git a/boa/src/builtins/array_buffer/mod.rs b/boa/src/builtins/array_buffer/mod.rs index acb57174c6..36597a5c7f 100644 --- a/boa/src/builtins/array_buffer/mod.rs +++ b/boa/src/builtins/array_buffer/mod.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::{ builtins::{typed_array::TypedArrayName, BuiltIn, JsArgs}, context::StandardObjects, @@ -313,11 +316,7 @@ impl ArrayBuffer { obj.set_prototype(prototype.into()); // 2. Let block be ? CreateByteDataBlock(byteLength). - // TODO: for now just a arbitrary limit to not OOM. - if byte_length > 8589934592 { - return Err(context.construct_range_error("ArrayBuffer allocation failed")); - } - let block = vec![0; byte_length]; + let block = create_byte_data_block(byte_length, context)?; // 3. Set obj.[[ArrayBufferData]] to block. // 4. Set obj.[[ArrayBufferByteLength]] to byteLength. @@ -733,6 +732,27 @@ impl ArrayBuffer { } } +/// `CreateByteDataBlock ( size )` abstract operation. +/// +/// The abstract operation `CreateByteDataBlock` takes argument `size` (a non-negative +/// integer). For more information, check the [spec][spec]. +/// +/// [spec]: https://tc39.es/ecma262/#sec-createbytedatablock +pub fn create_byte_data_block(size: usize, context: &mut Context) -> JsResult> { + // 1. Let db be a new Data Block value consisting of size bytes. If it is impossible to + // create such a Data Block, throw a RangeError exception. + let mut data_block = Vec::new(); + data_block.try_reserve(size).map_err(|e| { + context.construct_range_error(format!("couldn't allocate the data block: {}", e)) + })?; + + // 2. Set all of the bytes of db to 0. + data_block.resize(size, 0); + + // 3. Return db. + Ok(data_block) +} + /// `6.2.8.3 CopyDataBlockBytes ( toBlock, toIndex, fromBlock, fromIndex, count )` /// /// More information: diff --git a/boa/src/builtins/array_buffer/tests.rs b/boa/src/builtins/array_buffer/tests.rs new file mode 100644 index 0000000000..4f50ca9b12 --- /dev/null +++ b/boa/src/builtins/array_buffer/tests.rs @@ -0,0 +1,15 @@ +use super::*; + +#[test] +fn ut_sunnyy_day_create_byte_data_block() { + let mut context = Context::new(); + + assert!(create_byte_data_block(100, &mut context).is_ok()) +} + +#[test] +fn ut_rainy_day_create_byte_data_block() { + let mut context = Context::new(); + + assert!(create_byte_data_block(usize::MAX, &mut context).is_err()) +} diff --git a/boa/src/builtins/typed_array/integer_indexed_object.rs b/boa/src/builtins/typed_array/integer_indexed_object.rs index e4b7ab066f..cf29aacad5 100644 --- a/boa/src/builtins/typed_array/integer_indexed_object.rs +++ b/boa/src/builtins/typed_array/integer_indexed_object.rs @@ -12,7 +12,7 @@ use crate::{ builtins::typed_array::TypedArrayName, gc::{empty_trace, Finalize, Trace}, object::{JsObject, ObjectData}, - Context, JsResult, + Context, }; /// Type of the array content. @@ -147,38 +147,3 @@ impl IntegerIndexed { self.array_length = array_length; } } - -/// A Data Block -/// -/// The Data Block specification type is used to describe a distinct and mutable sequence of -/// byte-sized (8 bit) numeric values. A byte value is an integer value in the range `0` through -/// `255`, inclusive. A Data Block value is created with a fixed number of bytes that each have -/// the initial value `0`. -/// -/// For more information, check the [spec][spec]. -/// -/// [spec]: https://tc39.es/ecma262/#sec-data-blocks -#[derive(Debug, Clone, Default, Trace, Finalize)] -pub struct DataBlock { - inner: Vec, -} - -impl DataBlock { - /// `CreateByteDataBlock ( size )` abstract operation. - /// - /// The abstract operation `CreateByteDataBlock` takes argument `size` (a non-negative - /// integer). For more information, check the [spec][spec]. - /// - /// [spec]: https://tc39.es/ecma262/#sec-createbytedatablock - pub fn create_byte_data_block(size: usize) -> JsResult { - // 1. Let db be a new Data Block value consisting of size bytes. If it is impossible to - // create such a Data Block, throw a RangeError exception. - // 2. Set all of the bytes of db to 0. - // 3. Return db. - // TODO: waiting on for having fallible - // allocation. - Ok(Self { - inner: vec![0u8; size], - }) - } -}