Skip to content

Commit 2effc28

Browse files
committed
ffi: pass non-empty slice when haystack is empty
To work around likely bugs in (older versions of) PCRE2. Namely, at one point, PCRE2 would dereference the haystack pointer even when the length was zero. This was reported in #10 and we worked around this in #11 by passing a pointer to a const `&[]`, with the (erroneous) presumption that this would be a valid pointer to dereference. In retrospect though, this was a little silly, because you should never be dereferencing a pointer to an empty slice. It's not valid. Alas, at that time, Rust did actually hand you a valid pointer that could be dereferenced. But [this PR][rust-pull] changed that. And thus, we're back to where we started: handing buggy versions of PCRE2 a zero length haystack with a dangling pointer. So we fix this once and for all by passing a slice of length 1, but with a haystack length of 0, to the PCRE2 search routine when searching an empty haystack. This will guarantee the provision of a dereferencable pointer should PCRE2 decide to dereference it. Fixes #42 [rust-pull]: rust-lang/rust#123936
1 parent fbce64a commit 2effc28

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

src/ffi.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -433,20 +433,35 @@ impl MatchData {
433433
start: usize,
434434
options: u32,
435435
) -> Result<bool, Error> {
436-
// When the subject is empty, we use an empty slice
437-
// with a known valid pointer. Otherwise, slices derived
438-
// from, e.g., an empty `Vec<u8>` may not have a valid
439-
// pointer, since creating an empty `Vec` is guaranteed
440-
// to not allocate.
441-
const EMPTY: &[u8] = &[];
436+
// When the subject is empty, we use an NON-empty slice with a known
437+
// valid pointer. Otherwise, slices derived from, e.g., an empty
438+
// `Vec<u8>` may not have a valid pointer, since creating an empty
439+
// `Vec` is guaranteed to not allocate.
440+
//
441+
// We use a non-empty slice since it is otherwise difficult
442+
// to guarantee getting a dereferencable pointer. Which makes
443+
// sense, because the slice is empty, the pointer should never be
444+
// dereferenced!
445+
//
446+
// Alas, older versions of PCRE2 did exactly this. While that bug has
447+
// been fixed a while ago, it still seems to pop up[1]. So we try
448+
// harder.
449+
//
450+
// Note that even though we pass a non-empty slice in this case, we
451+
// still pass a length of zero. This just provides a pointer that won't
452+
// explode if you try to dereference it.
453+
//
454+
// [1]: https://github.com/BurntSushi/rust-pcre2/issues/42
455+
static SINGLETON: &[u8] = &[0];
456+
let len = subject.len();
442457
if subject.is_empty() {
443-
subject = EMPTY;
458+
subject = SINGLETON;
444459
}
445460

446461
let rc = pcre2_match_8(
447462
code.as_ptr(),
448463
subject.as_ptr(),
449-
subject.len(),
464+
len,
450465
start,
451466
options,
452467
self.as_mut_ptr(),

0 commit comments

Comments
 (0)