diff --git a/CHANGELOG.md b/CHANGELOG.md index f16c3fe84..f2949720f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +1.4.5 (2021-03-14) +================== +This is a small patch release that fixes a regression in the size of a `Regex` +in the 1.4.4 release. Prior to 1.4.4, a `Regex` was 552 bytes. In the 1.4.4 +release, it was 856 bytes due to internal changes. In this release, a `Regex` +is now 16 bytes. In general, the size of a `Regex` was never something that was +on my radar, but this increased size in the 1.4.4 release seems to have crossed +a threshold and resulted in stack overflows in some programs. + +* [BUG #750](https://github.com/rust-lang/regex/pull/750): + Fixes stack overflows seemingly caused by a large `Regex` size by decreasing + its size. + + 1.4.4 (2021-03-11) ================== This is a small patch release that contains some bug fixes. Notably, it also diff --git a/src/exec.rs b/src/exec.rs index 3fd7cc451..3d5a52bea 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -36,7 +36,14 @@ pub struct Exec { /// All read only state. ro: Arc, /// A pool of reusable values for the various matching engines. - pool: Pool, + /// + /// Note that boxing this value is not strictly necessary, but it is an + /// easy way to ensure that T does not bloat the stack sized used by a pool + /// in the case where T is big. And this turns out to be the case at the + /// time of writing for regex's use of this pool. At the time of writing, + /// the size of a Regex on the stack is 856 bytes. Boxing this value + /// reduces that size to 16 bytes. + pool: Box>, } /// `ExecNoSync` is like `Exec`, except it embeds a reference to a cache. This @@ -1446,11 +1453,11 @@ impl ExecReadOnly { lcs_len >= 3 && lcs_len > self.dfa.prefixes.lcp().char_len() } - fn new_pool(ro: &Arc) -> Pool { + fn new_pool(ro: &Arc) -> Box> { let ro = ro.clone(); - Pool::new(Box::new(move || { + Box::new(Pool::new(Box::new(move || { AssertUnwindSafe(RefCell::new(ProgramCacheInner::new(&ro))) - })) + }))) } } diff --git a/tests/test_default.rs b/tests/test_default.rs index e66a34ecf..af634a0c5 100644 --- a/tests/test_default.rs +++ b/tests/test_default.rs @@ -136,3 +136,18 @@ fn oibits_regression() { let _ = panic::catch_unwind(|| Regex::new("a").unwrap()); } + +// See: https://github.com/rust-lang/regex/issues/750 +#[test] +#[cfg(target_pointer_width = "64")] +fn regex_is_reasonably_small() { + use std::mem::size_of; + + use regex::bytes; + use regex::{Regex, RegexSet}; + + assert_eq!(16, size_of::()); + assert_eq!(16, size_of::()); + assert_eq!(16, size_of::()); + assert_eq!(16, size_of::()); +}