Hi,
I found a potential memory safety issue in the AsciiSet implementation through Kani formal verification.
Location: src/ascii_set.rs:47, 58, 64
Current Code:
const ASCII_RANGE_LEN: usize = 0x80; // 128
const BITS_PER_CHUNK: usize = 32;
pub struct AsciiSet {
mask: [Chunk; ASCII_RANGE_LEN / BITS_PER_CHUNK], // [u32; 4]
}
impl AsciiSet {
pub(crate) const fn contains(&self, byte: u8) -> bool {
let chunk = self.mask[byte as usize / BITS_PER_CHUNK]; // OOB when byte >= 128!
// …
}
pub const fn add(&self, byte: u8) -> Self {
mask[byte as usize / BITS_PER_CHUNK] |= ... // OOB when byte >= 128!
// ...
}
pub const fn remove(&self, byte: u8) -> Self {
mask[byte as usize / BITS_PER_CHUNK] &= ... // OOB when byte >= 128!
// ...
}
}
Analysis:
Array mask has 4 elements (valid indices: 0-3)
Index calculation: byte as usize / 32
For byte >= 128: index >= 4 (out of bounds)
Current Mitigation:
The documentation mentions this is for ASCII only, and should_percent_encode() checks is_ascii() before calling. However, add() and remove() are public API.
Impact:
Potential out-of-bounds memory access
Undefined behavior
Security concern if untrusted input reaches these methods
Suggested Fix:
pub(crate) const fn contains(&self, byte: u8) -> bool {
if byte >= 0x80 { return false; }
let chunk = self.mask[byte as usize / BITS_PER_CHUNK];
let mask = 1 << (byte as usize % BITS_PER_CHUNK);
(chunk & mask) != 0
}
pub const fn add(&self, byte: u8) -> Self {
let mut mask = self.mask;
if byte < 0x80 {
mask[byte as usize / BITS_PER_CHUNK] |= 1 << (byte as usize % BITS_PER_CHUNK);
}
Self { mask }
}
Could you please confirm if this is a valid security concern?
Hi,
I found a potential memory safety issue in the AsciiSet implementation through Kani formal verification.
Location: src/ascii_set.rs:47, 58, 64
Current Code:
const ASCII_RANGE_LEN: usize = 0x80; // 128
const BITS_PER_CHUNK: usize = 32;
pub struct AsciiSet {
mask: [Chunk; ASCII_RANGE_LEN / BITS_PER_CHUNK], // [u32; 4]
}
impl AsciiSet {
pub(crate) const fn contains(&self, byte: u8) -> bool {
let chunk = self.mask[byte as usize / BITS_PER_CHUNK]; // OOB when byte >= 128!
// …
}
pub const fn add(&self, byte: u8) -> Self {
mask[byte as usize / BITS_PER_CHUNK] |= ... // OOB when byte >= 128!
// ...
}
pub const fn remove(&self, byte: u8) -> Self {
mask[byte as usize / BITS_PER_CHUNK] &= ... // OOB when byte >= 128!
// ...
}
}
Analysis:
Array mask has 4 elements (valid indices: 0-3)
Index calculation: byte as usize / 32
For byte >= 128: index >= 4 (out of bounds)
Current Mitigation:
The documentation mentions this is for ASCII only, and should_percent_encode() checks is_ascii() before calling. However, add() and remove() are public API.
Impact:
Potential out-of-bounds memory access
Undefined behavior
Security concern if untrusted input reaches these methods
Suggested Fix:
pub(crate) const fn contains(&self, byte: u8) -> bool {
if byte >= 0x80 { return false; }
let chunk = self.mask[byte as usize / BITS_PER_CHUNK];
let mask = 1 << (byte as usize % BITS_PER_CHUNK);
(chunk & mask) != 0
}
pub const fn add(&self, byte: u8) -> Self {
let mut mask = self.mask;
if byte < 0x80 {
mask[byte as usize / BITS_PER_CHUNK] |= 1 << (byte as usize % BITS_PER_CHUNK);
}
Self { mask }
}
Could you please confirm if this is a valid security concern?