Skip to content

Commit fadf4e9

Browse files
authored
wasmparser: Implement no-hash-maps crate feature & support (#1521)
* move map.rs into its own folder * add no-hash-maps crate feature to wasmparser Disabled by default. * rename Hash{Map,Set} type aliases to just Map,Set * switch to BTree{Map,Set} if no-hash-maps is enabled This introduced a lot of compile errors in case no-hash-maps is actually enabled since many keys are not Ord. * use BTree{Map,Set} type aliases with no-hash-maps Some methods are not shared between Hash{Map,Set} and BTree{Map,Set} such as reserve and the Key type has different trait bounds (Eq + Hash) vs (Eq + Ord) which can be confusing when using map and set in wasmparser during development. Thus we actually do not want to use type aliases but proper types that wraps both Hash{Map,Set} and BTree{Map,Set} and provide a unified API. The same is true for Index{Map,Set} but we will do this in another commit. * fix intradoc links * cfg instead of comment out This is just a workaround until the new Map/Set type with unified API is done. * move random state definition into their own file I want to keep the base mod.rs as clean as possible. * rename map module to collections * rename random_state.rs -> hash.rs and make mod pub * restructure collections module * fix docs * add Entry type def to map data structures * update Set docs * turn the Set type alias into an opaque type Currently it only supports mostly the minimal API needed to make the wasmparser crate work. * add Clone derive for Set * turn the map type into an opaque type Currently it only mostly supports the minimal API needed to make the wasmparser crate work again. * fix workspace uses of wasparser collection types * apply rustfmt * add Iterator API for Set * add Iterator API to Map * simplify type defs and cfg guards * remove unnecessary cfg guard * simplify type aliases * add IterMut for Map * improve doc links * add FromIterator impls for Map and Set They are used in IndexMap so for symmetry I add them here too. * add Map::reserve symmetry: this method is used by both Set and IndexMap * add IntoIterator API for Map and Set symmetry: used on IndexMap * add Keys, Values and ValuesMut iterators for Map * improve docs of iter_mut * add doc link * add Map::contains_key * add doc link * add Index trait impl for Map * add Extent trait impl for Map and Set * update collections module docs * add doc comment * move Ord trait bound into impl * apply rustfmt * implement Ord and PartialOrd for KebabString * fix errors with upcoming IndexMap type usage * add IndexMap wrapper type This is still missing the custom IndexMap implementation when `no-hash-maps` is enabled. * add missing Index<usize> impl to IndexMap * add IndexMap::swap_remove used by IndexSet within wasmparser. We add this to keep APIs as mirrored as possible. * add doc link in doc comment for Set * add Set::replace Used by IndexSet in wasmparser. Keep this for API mirroring. * add basic set methods: Set::{is_disjoint, is_subset, is_superset} * PartialOrd and Ord impls for some types that were still missing them This is for IndexSet opaque type usage to work. * add opaque IndexSet type This does not yet support the custom implementation that avoid usage of hash maps internally. * improve collections module docs * improve docs of [Index]{Hash,Set} types * apply rustfmt * remove OccupiedEntry::[swap_]remove We removed this API because it was unused in wasmparser and implementing it on the custom BTreeMap based IndexMap is very cumbersome to do. * add BTreeMap based IndexMap backend This required us to add some Clone trait bounds to parts of the IndexMap API. * properly mirrior internal insert_full signature * add opaque IndexSet type * add where bounds to FusedIterator impls * remove unused import * add forwarding size_hint impls * fix bug in detail::IndexMap::is_empty * add GitHub CI job for no-hash-maps crate feature testing * simplify API surface of detail::IndexSet * base IndexSet impl on IndexMap<T, ()> * complete wasmparser::collections::Map shared API surface * complete wasmparser::collections::Set shared API surface * fix no-hash-maps compile error * fix bug in IndexMap::swap_remove_full impl For the no-hash-maps custom impl. * properly fix swap_remove_full and apply fmt * fix doc links * always compile custom IndexMap implementation This is friendlier for maintenance and developers. * add tests for custom IndexMap implementation
1 parent 443fc54 commit fadf4e9

18 files changed

Lines changed: 3543 additions & 70 deletions

File tree

.github/workflows/main.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ jobs:
5656
name: bins-${{ matrix.build }}
5757
path: dist
5858

59+
test-no-hash-maps:
60+
name: Test (no-hash-maps)
61+
runs-on: ubuntu-latest
62+
steps:
63+
- uses: actions/checkout@v4
64+
with:
65+
submodules: true
66+
- name: Install Rust
67+
run: rustup update stable --no-self-update && rustup default stable
68+
- name: Test (no-hash-maps)
69+
run: cargo test --workspace --locked --features no-hash-maps
70+
5971
test:
6072
name: Test
6173
runs-on: ${{ matrix.os }}

crates/wasm-compose/src/encoding.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,10 @@ impl<'a> TypeEncoder<'a> {
730730
index
731731
}
732732

733-
fn flags(encodable: &mut Encodable, names: &wasmparser::map::IndexSet<KebabString>) -> u32 {
733+
fn flags(
734+
encodable: &mut Encodable,
735+
names: &wasmparser::collections::IndexSet<KebabString>,
736+
) -> u32 {
734737
let index = encodable.type_count();
735738
encodable
736739
.ty()
@@ -739,7 +742,10 @@ impl<'a> TypeEncoder<'a> {
739742
index
740743
}
741744

742-
fn enum_type(encodable: &mut Encodable, cases: &wasmparser::map::IndexSet<KebabString>) -> u32 {
745+
fn enum_type(
746+
encodable: &mut Encodable,
747+
cases: &wasmparser::collections::IndexSet<KebabString>,
748+
) -> u32 {
743749
let index = encodable.type_count();
744750
encodable
745751
.ty()

crates/wasmparser/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ default = ['std', 'validate']
4545
# library's source of randomness for seeding hash maps.
4646
std = ['indexmap/std']
4747

48+
# Tells the wasmparser crate to avoid using hash based maps and sets.
49+
#
50+
# Some embedded environments cannot provide a random source which is required
51+
# to properly initialize hashmap based data structures for resilience against
52+
# malious actors that control their inputs.
53+
no-hash-maps = []
4854
# A feature that enables validating WebAssembly files. This is enabled by
4955
# default but not required if you're only parsing a file, for example, as
5056
# opposed to validating all of its contents.
Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,7 @@
1-
//! Type aliases for maps used by `wasmparser`
2-
//!
3-
//! This module contains type aliases used for [`HashMap`], [`HashSet`],
4-
//! [`IndexMap`], and [`IndexSet`]. Note that these differ from upstream types
5-
//! in the `indexmap` crate and the standard library due to customization of the
6-
//! hash algorithm type parameter.
1+
//! Utilities for hashmap initialization based on random sources.
72
83
use core::hash::{BuildHasher, Hasher};
94

10-
/// Wasmparser-specific type alias for an ordered map.
11-
pub type IndexMap<K, V> = indexmap::IndexMap<K, V, RandomState>;
12-
13-
/// Wasmparser-specific type alias for an ordered set.
14-
pub type IndexSet<K> = indexmap::IndexSet<K, RandomState>;
15-
16-
/// Wasmparser-specific type alias for hash map.
17-
pub type HashMap<K, V> = hashbrown::HashMap<K, V, RandomState>;
18-
19-
/// Wasmparser-specific type alias for hash set.
20-
pub type HashSet<K> = hashbrown::HashSet<K, RandomState>;
21-
225
/// Wasmparser's hashing state stored per-map.
236
///
247
/// This is DoS-resistant when the `std` feature is activated and still somewhat

0 commit comments

Comments
 (0)