Skip to content

Commit 90ff85e

Browse files
authored
rand v0.8.7: backport #1790 (#1804)
1 parent 5309f25 commit 90ff85e

5 files changed

Lines changed: 78 additions & 25 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).
88

99
You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.
1010

11+
## [0.8.7] - 2026-07-02
12+
### Fixes
13+
- Fix possible memory safety violation due to deserialization of `UniformChar` from bad source ([#1804])
14+
15+
[#1804]: https://github.com/rust-random/rand/pull/1804
16+
1117
## [0.8.6] - 2026-04-14
1218
This release back-ports a fix from v0.10. See also [#1763].
1319

Cargo.lock.msrv

Lines changed: 25 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rand"
3-
version = "0.8.6"
3+
version = "0.8.7"
44
authors = ["The Rand Project Developers", "The Rust Project Developers"]
55
license = "MIT OR Apache-2.0"
66
readme = "README.md"
@@ -76,3 +76,4 @@ libc = { version = "0.2.22", optional = true, default-features = false }
7676
rand_pcg = { path = "rand_pcg", version = "0.3.0" }
7777
# Only to test serde1
7878
bincode = "1.2.1"
79+
serde_json = "1.0.99"

src/distributions/uniform.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,15 @@ pub struct UniformInt<X> {
426426

427427
macro_rules! uniform_int_impl {
428428
($ty:ty, $unsigned:ident, $u_large:ident) => {
429+
impl UniformInt<$ty> {
430+
/// Get the maximum possible value
431+
#[allow(unused)]
432+
#[inline]
433+
pub(crate) fn max(&self) -> $ty {
434+
self.range.wrapping_sub(1).wrapping_add(self.low)
435+
}
436+
}
437+
429438
impl SampleUniform for $ty {
430439
type Sampler = UniformInt<$ty>;
431440
}
@@ -583,9 +592,24 @@ impl SampleUniform for char {
583592
#[derive(Clone, Copy, Debug)]
584593
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
585594
pub struct UniformChar {
595+
#[cfg_attr(feature = "serde1", serde(deserialize_with = "deser_sampler"))]
586596
sampler: UniformInt<u32>,
587597
}
588598

599+
#[cfg(feature = "serde1")]
600+
fn deser_sampler<'de, D>(d: D) -> Result<UniformInt<u32>, D::Error>
601+
where
602+
D: serde::Deserializer<'de>,
603+
{
604+
let sampler = <UniformInt<u32> as serde::Deserialize>::deserialize(d)?;
605+
if sampler.max() > std::char::MAX as u32 - CHAR_SURROGATE_LEN {
606+
return Err(serde::de::Error::custom(
607+
"bad sampler range for UniformChar",
608+
));
609+
}
610+
Ok(sampler)
611+
}
612+
589613
/// UTF-16 surrogate range start
590614
const CHAR_SURROGATE_START: u32 = 0xD800;
591615
/// UTF-16 surrogate range size
@@ -1154,6 +1178,24 @@ mod tests {
11541178
}
11551179
}
11561180

1181+
#[test]
1182+
#[cfg(feature = "serde1")]
1183+
fn test_char_bad_deser() {
1184+
let json = r#"{"sampler":{"low":4294967200,"range":0,"z":0}}"#;
1185+
let result = serde_json::from_str::<Uniform<char>>(json);
1186+
assert!(result.is_err());
1187+
let err = result.unwrap_err();
1188+
assert_eq!(err.classify(), serde_json::error::Category::Data);
1189+
1190+
#[cfg(feature = "alloc")]
1191+
{
1192+
assert_eq!(
1193+
alloc::string::ToString::to_string(&err),
1194+
"bad sampler range for UniformChar at line 1 column 46"
1195+
);
1196+
}
1197+
}
1198+
11571199
#[test]
11581200
#[cfg_attr(miri, ignore)] // Miri is too slow
11591201
fn test_floats() {
@@ -1381,6 +1423,7 @@ mod tests {
13811423
let r = Uniform::from(2u32..7);
13821424
assert_eq!(r.0.low, 2);
13831425
assert_eq!(r.0.range, 5);
1426+
assert_eq!(r.0.max(), 6);
13841427
let r = Uniform::from(2.0f64..7.0);
13851428
assert_eq!(r.0.low, 2.0);
13861429
assert_eq!(r.0.scale, 5.0);
@@ -1391,6 +1434,7 @@ mod tests {
13911434
let r = Uniform::from(2u32..=6);
13921435
assert_eq!(r.0.low, 2);
13931436
assert_eq!(r.0.range, 5);
1437+
assert_eq!(r.0.max(), 6);
13941438
let r = Uniform::from(2.0f64..=7.0);
13951439
assert_eq!(r.0.low, 2.0);
13961440
assert!(r.0.scale > 5.0);

src/seq/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,7 @@ mod test {
13101310

13111311
#[test]
13121312
#[cfg(feature = "std")]
1313+
#[cfg_attr(miri, ignore)] // Miri is too slow
13131314
fn test_multiple_weighted_distributions() {
13141315
use super::*;
13151316

0 commit comments

Comments
 (0)