Change:
Hello When playing with some development versions of tower-grpc-build (), I discovered a strange crash of the build script. I managed to shring it a bit, but I don't think this is minimal case (I just don't know how to continue pinning it down further). Few observations: The string it talks about in the backtrace seems like random junk (which isn't always the same). I'm not sure how it got there, but in general, Rust probably should prevent creation of strings with uninitialized content. It doesn't happen on stable. It happens on today's and yesterday's nightly (exact version below). It doesn't happen on approx. a week old nightly, but I'm not at the computer that has the older version, I'll look exact version when I get to it in few hours. As I needed to pin exact commits in to make the branches and crates from git to compile together, I have the example as a whole repository: Steps to reproduce (I moved the failing code from build script to ordinary , therefore the ): The backtrace: It is likely something fishy is happening in some of the development branches, but I still suspect something strange happening in the compiler, both because of the uninitialized memory (or, memory looking uninitialized) and because it passes on stable, but not nightly.
cc -- any chance somebody can bisect this a bit to see where the problem started?
triage: P-high
If it helps, this one goes through (): And this one fails (): Anything more exact would need setting up of some non-trivial infrastructure on my own computer.
Given the range ... I'm pretty sure it is , but let me bisect anyway... Edit: failed due to procmacro` ಠಠ needs to reduce it first.
cc
Reductions: <details<summaryReducing dependency to <codeprost_build</code.</summary</detailsall dependencies. Repro on playground. Edit: Hold on, this program affects beta (1.24.0-beta.1) as well
Bisecting in the range ... Test script: ( has content shown in ) Bisect result: So yeah the cause is definitely , and since it slips into beta it affects 1.24 beta as well.
Huh. Wat. I'll fix this tomorrow.
Okay, so the bug seems to be a discrepancy in how I thought the searcher API is supposed to work. in old Rust this returns Some(1,2) and None, in new Rust it returns the same thing twice. I was under the impression that double ended searchers had independent fingers, but this seems to be wrong. We really need to overhaul this API so that it actually makes sense.
Fixed in r?
Our build is crashing through this bug. Nightly is green again after this PR was merged, however beta is still red. Will beta still be rolled out to stable and break our build in a few weeks? Or will there be a beta hotfix with this PR included?
Yes we are going to backport to 1.24 beta.
It's been marked beta-nominated, so it will be included before we make a stable release. I don't know if it will be included in a new beta before that. Either way, I'm the wrong person to ask, would know
Yes, we will (likely) publish a new beta with this backport. There's 5(?) weeks before the next release, so we'll need at least 2-3 more betas probably
Awesome! Thanks for clarifying.
I believe the latest beta should have the fix (.2).

Discussion:
#[inline] fn next(&mut self) -> SearchStep { let old_finger = self.finger; <del> let slice = unsafe { self.haystack.get_unchecked(old_finger..self.haystack.len()) }; </del> <ins> let slice = unsafe { self.haystack.get_unchecked(old_finger..self.finger_back) }; </ins> let mut iter = slice.chars(); let old_len = iter.iter.len(); if let Some(ch) = iter.next() {

fn next_match(&mut self) -> Option<(usize, usize)> { loop { // get the haystack after the last character found <del> let bytes = if let Some(slice) = self.haystack.as_bytes().get(self.finger..) { </del> <ins> let bytes = if let Some(slice) = self.haystack.as_bytes() .get(self.finger..self.finger_back) { </ins> slice } else { return None;

} } else { // found nothing, exit <del> self.finger = self.haystack.len(); </del> <ins> self.finger = self.finger_back; </ins> return None; } }

#[inline] fn next_back(&mut self) -> SearchStep { let old_finger = self.finger_back; <del> let slice = unsafe { self.haystack.slice_unchecked(0, old_finger) }; </del> <ins> let slice = unsafe { self.haystack.slice_unchecked(self.finger, old_finger) }; </ins> let mut iter = slice.chars(); let old_len = iter.iter.len(); if let Some(ch) = iter.next_back() {

let haystack = self.haystack.as_bytes(); loop { // get the haystack up to but not including the last character searched <del> let bytes = if let Some(slice) = haystack.get(..self.finger_back) { </del> <ins> let bytes = if let Some(slice) = haystack.get(self.finger..self.finger_back) { </ins> slice } else { return None;

// the last byte of the utf8 encoded needle let last_byte = unsafe { *self.utf8_encoded.get_unchecked(self.utf8_size - 1) }; if let Some(index) = memchr::memrchr(last_byte, bytes) { <ins> // we searched a slice that was offset by self.finger, // add self.finger to recoup the original index let index = self.finger + index; </ins> // memrchr will return the index of the byte we wish to // find. In case of an ASCII character, this is indeed // were we wish our new finger to be ("after" the found

// found the last byte when searching in reverse. self.finger_back = index; } else { <del> self.finger_back = 0; </del> <ins> self.finger_back = self.finger; </ins> // found nothing, exit return None; }

[InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done] ); } <ins> #[test] fn double_ended_regression_test() { // https://github.com/rust-lang/rust/issues/47175 // Ensures that double ended searching comes to a convergence search_asserts!("abcdeabcdeabcde", 'a', "alternating double ended search", [next_match,    next_match_back,    next_match,      next_match_back], [InRange(0, 1), InRange(10, 11), InRange(5, 6), Done] ); search_asserts!("abcdeabcdeabcde", 'a', "triple double ended search for a", [next_match,    next_match_back,    next_match_back,      next_match_back], [InRange(0, 1), InRange(10, 11), InRange(5, 6), Done] ); search_asserts!("abcdeabcdeabcde", 'd', "triple double ended search for d", [next_match,    next_match_back,    next_match_back,      next_match_back], [InRange(3, 4), InRange(13, 14), InRange(8, 9), Done] ); search_asserts!(STRESS, 'Á', "Double ended search for two-byte Latin character", [next_match,    next_match_back,     next_match,      next_match_back], [InRange(0, 2), InRange(32, 34), InRange(8, 10), Done] ); search_asserts!(STRESS, '각', "Reverse double ended search for three-byte Hangul character", [next_match_back, next_back,       next_match,      next,            next_match_back, next_match], [InRange(34, 37), Rejects(32, 34), InRange(19, 22), Rejects(22, 25), InRange(28, 31), Done] ); search_asserts!(STRESS, 'ก', "Double ended search for three-byte Thai character", [next_match,      next_back,       next,            next_match_back, next_match], [InRange(22, 25), Rejects(47, 48), Rejects(25, 28), InRange(40, 43), Done] ); search_asserts!(STRESS, '😁', "Double ended search for four-byte emoji", [next_match_back, next,          next_match,      next_back,       next_match], [InRange(43, 47), Rejects(0, 2), InRange(15, 19), Rejects(40, 43), Done] ); search_asserts!(STRESS, 'ꁁ', "Double ended search for three-byte Yi character with repeated bytes", [next_match,      next,            next_match_back, next_back,       next_match], [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(34, 37), Done] ); } </ins>