1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! 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(Clone, Debug)]
#[cfg(not(feature = "std"))]
struct RandomStateImpl {
    state: ahash::RandomState,
}

#[cfg(not(feature = "std"))]
impl Default for RandomStateImpl {
    fn default() -> RandomStateImpl {
        RandomStateImpl {
            state: ahash::RandomState::new(),
        }
    }
}

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

    #[inline]
    fn build_hasher(&self) -> ahash::AHasher {
        self.state.build_hasher()
    }
}