Skip to content

Commit 0107188

Browse files
committed
Harden strict decode backend boundary tests
1 parent 4fad417 commit 0107188

2 files changed

Lines changed: 85 additions & 1 deletion

File tree

src/decode_backend.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ pub(crate) fn active_decode_backend() -> DecodeBackend {
3333
DecodeBackend::Scalar
3434
}
3535

36-
/// Decodes `input` into `output` through the admitted decode backend.
36+
/// Decodes `input` into `output` through the admitted strict decode backend.
37+
///
38+
/// Only the normal strict `Engine::decode_slice` family enters this boundary.
39+
/// Legacy whitespace handling, wrapped decode, in-place decode, and `ct`
40+
/// secret decode remain separate scalar surfaces unless a future admission
41+
/// package explicitly adds and tests them.
3742
pub(crate) fn decode_slice<A, const PAD: bool>(
3843
input: &[u8],
3944
output: &mut [u8],

src/tests.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,37 @@ where
9999
}
100100
}
101101

102+
fn assert_strict_decode_public_surfaces_match_scalar<A, const PAD: bool>(input: &[u8])
103+
where
104+
A: Alphabet,
105+
{
106+
let engine = Engine::<A, PAD>::new();
107+
let mut slice_output = [0x55; 128];
108+
let mut clear_tail_output = [0xaa; 128];
109+
let mut scalar_output = [0xcc; 128];
110+
111+
let scalar_result = scalar::scalar_reference_decode_slice::<A, PAD>(input, &mut scalar_output);
112+
let slice_result = engine.decode_slice(input, &mut slice_output);
113+
let clear_tail_result = engine.decode_slice_clear_tail(input, &mut clear_tail_output);
114+
let buffer_result: Result<DecodedBuffer<128>, DecodeError> = engine.decode_buffer(input);
115+
116+
assert_eq!(slice_result, scalar_result);
117+
assert_eq!(clear_tail_result, scalar_result);
118+
match slice_result {
119+
Ok(written) => {
120+
assert_eq!(&slice_output[..written], &scalar_output[..written]);
121+
assert_eq!(&clear_tail_output[..written], &scalar_output[..written]);
122+
assert!(clear_tail_output[written..].iter().all(|byte| *byte == 0));
123+
let buffer = buffer_result.unwrap();
124+
assert_eq!(buffer.as_bytes(), &scalar_output[..written]);
125+
}
126+
Err(err) => {
127+
assert!(clear_tail_output.iter().all(|byte| *byte == 0));
128+
assert_eq!(buffer_result.unwrap_err(), err);
129+
}
130+
}
131+
}
132+
102133
fn assert_backend_round_trip_matches_scalar<A, const PAD: bool>(input: &[u8])
103134
where
104135
A: Alphabet,
@@ -179,6 +210,54 @@ fn backend_dispatch_matches_scalar_reference_for_malformed_inputs() {
179210
assert_decode_backend_matches_scalar::<Standard, false>(b"AA_A");
180211
}
181212

213+
#[test]
214+
fn strict_decode_public_surfaces_match_scalar_reference() {
215+
for input in [
216+
&b""[..],
217+
b"Zg==",
218+
b"Zm8=",
219+
b"Zm9v",
220+
b"Zm9vYg==",
221+
b"Zm9vYmE=",
222+
b"Zm9vYmFy",
223+
b"////",
224+
b"AAEC",
225+
] {
226+
assert_strict_decode_public_surfaces_match_scalar::<Standard, true>(input);
227+
}
228+
229+
for input in [
230+
&b""[..],
231+
b"Zg",
232+
b"Zm8",
233+
b"Zm9v",
234+
b"Zm9vYg",
235+
b"Zm9vYmE",
236+
b"Zm9vYmFy",
237+
b"____",
238+
b"AAEC",
239+
] {
240+
assert_strict_decode_public_surfaces_match_scalar::<UrlSafe, false>(input);
241+
}
242+
243+
for input in [
244+
&b"Z"[..],
245+
b"====",
246+
b"AA=A",
247+
b"Zh==",
248+
b"Zm9=",
249+
b"Zm9v$g==",
250+
b"Zm9vZh==",
251+
b"AA-A",
252+
] {
253+
assert_strict_decode_public_surfaces_match_scalar::<Standard, true>(input);
254+
}
255+
256+
for input in [&b"Z"[..], b"AA=A", b"Zh", b"Zm9", b"Zm9vYg$", b"AA/A"] {
257+
assert_strict_decode_public_surfaces_match_scalar::<UrlSafe, false>(input);
258+
}
259+
}
260+
182261
#[test]
183262
fn decode_chunk_bit_packing_matches_exhaustive_small_inputs() {
184263
for byte in u8::MIN..=u8::MAX {

0 commit comments

Comments
 (0)