Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support no_std in the wasmparser crate #1493

Merged
merged 2 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: rustup target add x86_64-unknown-none
- run: cargo check --benches -p wasm-smith
- run: cargo check --no-default-features
- run: cargo check --no-default-features --features print
Expand All @@ -176,6 +177,9 @@ jobs:
- run: cargo check --no-default-features -p wit-parser --features serde
- run: cargo check --no-default-features -p wit-parser --features decoding
- run: cargo check --no-default-features -p wit-parser --features serde,decoding,wat
- run: cargo check --no-default-features -p wasmparser
- run: cargo check --no-default-features -p wasmparser --target x86_64-unknown-none
- run: cargo check --no-default-features -p wasmparser --features std
- run: |
if cargo tree -p wasm-smith --no-default-features -e no-dev | grep wasmparser; then
echo wasm-smith without default features should not depend on wasmparser
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ clap = { version = "4.0.0", features = ["derive"] }
clap_complete = "4.4.7"
criterion = "0.3.3"
env_logger = "0.11"
indexmap = "2.0.0"
indexmap = { version = "2.0.0", default-features = false }
leb128 = "0.2.4"
libfuzzer-sys = "0.4.0"
log = "0.4.17"
Expand All @@ -55,10 +55,12 @@ serde_json = { version = "1" }
wasmtime = { version = "20.0.0", default-features = false, features = ['cranelift', 'component-model', 'runtime', 'gc'] }
url = "2.0.0"
pretty_assertions = "1.3.0"
semver = "1.0.0"
semver = { version = "1.0.0", default-features = false }
smallvec = "1.11.1"
libtest-mimic = "0.7.0"
bitflags = "2.5.0"
hashbrown = { version = "0.14.3", default-features = false, features = ['ahash'] }
ahash = { version = "0.8.11", default-features = false }

wasm-compose = { version = "0.205.0", path = "crates/wasm-compose" }
wasm-encoder = { version = "0.205.0", path = "crates/wasm-encoder" }
Expand Down
4 changes: 2 additions & 2 deletions crates/wasm-compose/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ impl<'a> TypeEncoder<'a> {
index
}

fn flags(encodable: &mut Encodable, names: &IndexSet<KebabString>) -> u32 {
fn flags(encodable: &mut Encodable, names: &wasmparser::map::IndexSet<KebabString>) -> u32 {
let index = encodable.type_count();
encodable
.ty()
Expand All @@ -739,7 +739,7 @@ impl<'a> TypeEncoder<'a> {
index
}

fn enum_type(encodable: &mut Encodable, cases: &IndexSet<KebabString>) -> u32 {
fn enum_type(encodable: &mut Encodable, cases: &wasmparser::map::IndexSet<KebabString>) -> u32 {
let index = encodable.type_count();
encodable
.ty()
Expand Down
6 changes: 6 additions & 0 deletions crates/wasmparser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ workspace = true
bitflags = "2.4.1"
indexmap = { workspace = true }
semver = { workspace = true }
hashbrown = { workspace = true }
ahash = { workspace = true }

[dev-dependencies]
anyhow = { workspace = true }
Expand All @@ -34,3 +36,7 @@ log.workspace = true
[[bench]]
name = "benchmark"
harness = false

[features]
default = ['std']
std = ['indexmap/std']
1 change: 0 additions & 1 deletion crates/wasmparser/LICENSE

This file was deleted.

15 changes: 8 additions & 7 deletions crates/wasmparser/src/binary_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
* limitations under the License.
*/

use crate::prelude::*;
use crate::{limits::*, *};
use std::error::Error;
use std::fmt;
use std::marker;
use std::ops::Range;
use std::str;
use core::fmt;
use core::marker;
use core::ops::Range;
use core::str;

pub(crate) const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm";

Expand All @@ -39,9 +39,10 @@ pub(crate) struct BinaryReaderErrorInner {
}

/// The result for `BinaryReader` operations.
pub type Result<T, E = BinaryReaderError> = std::result::Result<T, E>;
pub type Result<T, E = BinaryReaderError> = core::result::Result<T, E>;

impl Error for BinaryReaderError {}
#[cfg(feature = "std")]
impl std::error::Error for BinaryReaderError {}

impl fmt::Display for BinaryReaderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Expand Down
24 changes: 24 additions & 0 deletions crates/wasmparser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@
//! the examples documented for [`Parser::parse`] or [`Parser::parse_all`].
#![deny(missing_docs)]
#![no_std]

extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
fitzgen marked this conversation as resolved.
Show resolved Hide resolved

/// A small "prelude" to use throughout this crate.
///
/// This crate is tagged with `#![no_std]` meaning that we get libcore's prelude
/// by default. This crate also uses `alloc`, however, and common types there
/// like `String`. This custom prelude helps bring those types into scope to
/// avoid having to import each of them manually.
mod prelude {
pub use alloc::borrow::ToOwned;
pub use alloc::boxed::Box;
pub use alloc::format;
pub use alloc::string::{String, ToString};
pub use alloc::vec;
pub use alloc::vec::Vec;

pub use crate::map::{HashMap, HashSet, IndexMap, IndexSet};
}

/// A helper macro to conveniently iterate over all opcodes recognized by this
/// crate. This can be used to work with either the [`Operator`] enumeration or
Expand Down Expand Up @@ -770,3 +792,5 @@ mod parser;
mod readers;
mod resources;
mod validator;

pub mod map;
126 changes: 126 additions & 0 deletions crates/wasmparser/src/map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//! Type aliases for maps used by `wasmparser`
//!
//! This module contains type aliases used for [`HashMap`], [`HashSet`],
//! [`IndexMap`], and [`IndexSet`]. Note that these differ from upstream types
//! in the `indexmap` crate and the standard library due to customization of the
//! hash algorithm type parameter.
use core::hash::{BuildHasher, Hasher};

/// Wasmparser-specific type alias for an ordered map.
pub type IndexMap<K, V> = indexmap::IndexMap<K, V, RandomState>;

/// Wasmparser-specific type alias for an ordered set.
pub type IndexSet<K> = indexmap::IndexSet<K, RandomState>;

/// Wasmparser-specific type alias for hash map.
pub type HashMap<K, V> = hashbrown::HashMap<K, V, RandomState>;

/// Wasmparser-specific type alias for hash set.
pub type HashSet<K> = hashbrown::HashSet<K, RandomState>;

/// Wasmparser's hashing state stored per-map.
///
/// This is DoS-resistant when the `std` feature is activated and still somewhat
/// resistant when it's not active but not as secure.
#[derive(Clone, Debug)]
pub struct RandomState(RandomStateImpl);

impl Default for RandomState {
#[inline]
fn default() -> RandomState {
RandomState(RandomStateImpl::default())
}
}

impl BuildHasher for RandomState {
type Hasher = RandomStateHasher;

#[inline]
fn build_hasher(&self) -> RandomStateHasher {
RandomStateHasher(self.0.build_hasher())
}
}

/// Wasmparser's hasher type used with [`RandomState`].
pub struct RandomStateHasher(<RandomStateImpl as BuildHasher>::Hasher);

impl Hasher for RandomStateHasher {
#[inline]
fn finish(&self) -> u64 {
self.0.finish()
}
#[inline]
fn write(&mut self, bytes: &[u8]) {
self.0.write(bytes)
}
#[inline]
fn write_u8(&mut self, i: u8) {
self.0.write_u8(i)
}
#[inline]
fn write_u16(&mut self, i: u16) {
self.0.write_u16(i)
}
#[inline]
fn write_u32(&mut self, i: u32) {
self.0.write_u32(i)
}
#[inline]
fn write_u64(&mut self, i: u64) {
self.0.write_u64(i)
}
#[inline]
fn write_u128(&mut self, i: u128) {
self.0.write_u128(i)
}
#[inline]
fn write_usize(&mut self, i: usize) {
self.0.write_usize(i)
}
#[inline]
fn write_i8(&mut self, i: i8) {
self.0.write_i8(i)
}
#[inline]
fn write_i16(&mut self, i: i16) {
self.0.write_i16(i)
}
#[inline]
fn write_i32(&mut self, i: i32) {
self.0.write_i32(i)
}
#[inline]
fn write_i64(&mut self, i: i64) {
self.0.write_i64(i)
}
#[inline]
fn write_i128(&mut self, i: i128) {
self.0.write_i128(i)
}
#[inline]
fn write_isize(&mut self, i: isize) {
self.0.write_isize(i)
}
}

// When the `std` feature is active reuse the standard library's implementation
// of hash state and hasher.
#[cfg(feature = "std")]
use std::collections::hash_map::RandomState as RandomStateImpl;

// When the `std` feature is NOT active then rely on `ahash::RandomState`. That
// relies on ASLR by default for randomness.
#[derive(Default, Clone, Debug)]
#[cfg(not(feature = "std"))]
struct RandomStateImpl;

#[cfg(not(feature = "std"))]
impl BuildHasher for RandomStateImpl {
type Hasher = ahash::AHasher;

#[inline]
fn build_hasher(&self) -> ahash::AHasher {
ahash::RandomState::new().build_hasher()
}
}
Comment on lines +112 to +126
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense expose a method for manually setting the random state for nostd users that happen to have some source of randomness we don't (and can't) know about?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sort of already handled by the ahash crate itself although that's not quite the same as providing it through wasmparser itself. My thinking is given that this is going to be shared across Wasmtime and wasmparser it might be best to leave this to ahash for now and add it here if necessary in the future

9 changes: 5 additions & 4 deletions crates/wasmparser/src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::binary_reader::WASM_MAGIC_NUMBER;
use crate::prelude::*;
use crate::CoreTypeSectionReader;
use crate::{
limits::MAX_WASM_MODULE_SIZE, BinaryReader, BinaryReaderError, ComponentCanonicalSectionReader,
Expand All @@ -8,9 +9,9 @@ use crate::{
GlobalSectionReader, ImportSectionReader, InstanceSectionReader, MemorySectionReader, Result,
SectionLimited, TableSectionReader, TagSectionReader, TypeSectionReader,
};
use std::fmt;
use std::iter;
use std::ops::Range;
use core::fmt;
use core::iter;
use core::ops::Range;

pub(crate) const WASM_MODULE_VERSION: u16 = 0x1;

Expand Down Expand Up @@ -952,7 +953,7 @@ impl Parser {
///
/// ```
/// use wasmparser::{Result, Parser, Chunk, Payload::*};
/// use std::ops::Range;
/// use core::ops::Range;
///
/// fn objdump_headers(mut wasm: &[u8]) -> Result<()> {
/// let mut parser = Parser::new(0);
Expand Down
6 changes: 3 additions & 3 deletions crates/wasmparser/src/readers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
*/

use crate::{BinaryReader, BinaryReaderError, Result};
use std::fmt;
use std::marker;
use std::ops::Range;
use ::core::fmt;
use ::core::marker;
use ::core::ops::Range;

mod component;
mod core;
Expand Down
1 change: 1 addition & 0 deletions crates/wasmparser/src/readers/component/canonicals.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::limits::MAX_WASM_CANONICAL_OPTIONS;
use crate::prelude::*;
use crate::{BinaryReader, FromReader, Result, SectionLimited};

/// Represents options for component functions.
Expand Down
1 change: 1 addition & 0 deletions crates/wasmparser/src/readers/component/instances.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::limits::{MAX_WASM_INSTANTIATION_ARGS, MAX_WASM_INSTANTIATION_EXPORTS};
use crate::prelude::*;
use crate::{
BinaryReader, ComponentExport, ComponentExternalKind, Export, FromReader, Result,
SectionLimited,
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmparser/src/readers/component/names.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{BinaryReader, BinaryReaderError, NameMap, Result, Subsection, Subsections};
use std::ops::Range;
use core::ops::Range;

/// Type used to iterate and parse the contents of the `component-name` custom
/// section in compnents, similar to the `name` section of core modules.
Expand Down
1 change: 1 addition & 0 deletions crates/wasmparser/src/readers/component/start.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::limits::{MAX_WASM_FUNCTION_RETURNS, MAX_WASM_START_ARGS};
use crate::prelude::*;
use crate::{BinaryReader, FromReader, Result};

/// Represents the start function in a WebAssembly component.
Expand Down
5 changes: 3 additions & 2 deletions crates/wasmparser/src/readers/component/types.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::limits::*;
use crate::prelude::*;
use crate::{
BinaryReader, ComponentAlias, ComponentExportName, ComponentImport, ComponentTypeRef,
FromReader, Import, Result, SectionLimited, SubType, TypeRef, ValType,
};
use std::fmt;
use core::fmt;

/// Represents the kind of an outer core alias in a WebAssembly component.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -420,7 +421,7 @@ impl ComponentFuncResult<'_> {
}

match self {
Self::Unnamed(ty) => Either::Left(std::iter::once(ty).map(|ty| (None, ty))),
Self::Unnamed(ty) => Either::Left(core::iter::once(ty).map(|ty| (None, ty))),
Self::Named(vec) => Either::Right(vec.iter().map(|(n, ty)| (Some(*n), ty))),
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmparser/src/readers/core/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
*/

use crate::{BinaryReader, FromReader, OperatorsReader, Result, SectionLimited, ValType};
use std::ops::Range;
use core::ops::Range;

/// A reader for the code section of a WebAssembly module.
pub type CodeSectionReader<'a> = SectionLimited<'a, FunctionBody<'a>>;
Expand Down
1 change: 1 addition & 0 deletions crates/wasmparser/src/readers/core/coredumps.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::prelude::*;
use crate::{BinaryReader, FromReader, Result};

/// The data portion of a custom section representing a core dump. Per the
Expand Down
Loading
Loading