Skip to content

Commit

Permalink
Don't allocate an unnecessarily large buffer in decode_config
Browse files Browse the repository at this point in the history
Also, address a complaint from `cargo doc`.

NB: In practice 1.46.0 is needed to run tests due to dev dependencies, but I'm not addressing any MSRV changes since this will be supplanted by 1.0's higher MSRV anyway.
  • Loading branch information
marshallpierce committed Oct 21, 2022
1 parent b4fc913 commit efb0b53
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "base64"
version = "0.13.0"
version = "0.13.1"
authors = ["Alice Maz <alice@alicemaz.com>", "Marshall Pierce <marshall@mpierce.org>"]
description = "encodes and decodes base64 as bytes or utf8"
repository = "https://github.com/marshallpierce/rust-base64"
Expand Down
4 changes: 4 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.13.1

- More precise decode buffer sizing, avoiding unnecessary allocation in `decode_config`.

# 0.13.0

- Config methods are const
Expand Down
22 changes: 21 additions & 1 deletion src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,14 @@ pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError> {
///```
#[cfg(any(feature = "alloc", feature = "std", test))]
pub fn decode_config<T: AsRef<[u8]>>(input: T, config: Config) -> Result<Vec<u8>, DecodeError> {
let mut buffer = Vec::<u8>::with_capacity(input.as_ref().len() * 4 / 3);
let decoded_length_estimate = (input
.as_ref()
.len()
.checked_add(3)
.expect("decoded length calculation overflow"))
/ 4
* 3;
let mut buffer = Vec::<u8>::with_capacity(decoded_length_estimate);

decode_config_buf(input, config, &mut buffer).map(|_| buffer)
}
Expand Down Expand Up @@ -870,4 +877,17 @@ mod tests {
}
}
}

#[test]
fn decode_config_estimation_works_for_various_lengths() {
for num_prefix_quads in 0..100 {
for suffix in &["AA", "AAA", "AAAA"] {
let mut prefix = "AAAA".repeat(num_prefix_quads);
prefix.push_str(suffix);
// make sure no overflow (and thus a panic) occurs
let res = decode_config(prefix, STANDARD);
assert!(res.is_ok());
}
}
}
}
2 changes: 1 addition & 1 deletion src/write/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ impl<W: Write> Write for EncoderWriter<W> {
/// Under non-error circumstances, this returns `Ok` with the value being the number of bytes
/// of `input` consumed. The value may be `0`, which interacts poorly with `write_all`, which
/// interprets `Ok(0)` as an error, despite it being allowed by the contract of `write`. See
/// https://github.com/rust-lang/rust/issues/56889 for more on that.
/// <https://github.com/rust-lang/rust/issues/56889> for more on that.
///
/// If the previous call to `write` provided more (encoded) data than the delegate writer could
/// accept in a single call to its `write`, the remaining data is buffered. As long as buffered
Expand Down

0 comments on commit efb0b53

Please sign in to comment.