Change:
PR a x8664 SIMD-based implementation of to optimize searching into strings when the needle is at most 32 bytes long. Unfortunately, that implementation doesn't seem to be sound. When compiling the standard library with debug assertions on, running UI tests excluding results in compiletest itself panicking before executing any test due to a in libcore: To reproduce the issue, use the following configuration file: run: cc
Tentatively opened a revert PR in
Ugh. I ran it under miri with quite a combinatorial test that I thought should cover all the edge-cases. It's not immediately obvious what's wrong, so it's fine to land the revert for now.
Last I checked (and a lot has happened since then so I could be working on outdated info -- might be able to confirm), miri can't catch failure in many cases I believe, since it's "just" library UB.
the memory will be accessed after the get_unchecked so it should still be an invalid memory access when it's out of bounds. Unless I'm just doing some shortening slicing and then extending it again so that it's valid within the same allocation but not correct slicing.
What says is correct. The error here is in a situation like Miri (without Stacked Borrows) will not complain about that since the index is in-bounds of the allocation. But the debug assertion will complain since you are causing library UB by going out-of-bounds of the slice. I don't quite understand your last comment,
It seems like the test is just insufficient. Even with debug asserts and overflow checks enabled it doesn't catch it. I'll have to reproduce it first to figure out what's missing.
Ooh, I was getting absolutely unexplainable compiler errors when building stage 1 libstd with a stage 0 rustc which was built with however, could this be the cause for this? :sweat_smile:
Possible, but it would also do incorrect things on x86-64 baseline
has a proper fix

Discussion:
} #[test] <ins> fn strslice_issue_104726() { // Edge-case in the simd_contains impl. // The first and last byte are the same so it backtracks by one byte // which aligns with the end of the string. Previously incorrect offset calculations // lead to out-of-bounds slicing. #[rustfmt::skip] let needle =                        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaba"; let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"; assert!(!haystack.contains(needle)); } #[test] </ins> #[cfg_attr(miri, ignore)] // Miri is too slow fn test_strslice_contains() { let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'";

use crate::simd::{SimdPartialEq, ToBitMask}; let first_probe = needle[0]; <ins> let last_byte_offset = needle.len() - 1; </ins> // the offset used for the 2nd vector let second_probe_offset = if needle.len() == 2 {

}; // do a naive search if the haystack is too small to fit <del> if haystack.len() < Block::LANES + second_probe_offset { </del> <ins> if haystack.len() < Block::LANES + last_byte_offset { </ins> return Some(haystack.windows(needle.len()).any(|c| c == needle)); }

// The loop condition must ensure that there's enough headroom to read LANE bytes, // and not only at the current index but also at the index shifted by block_offset const UNROLL: usize = 4; <del> while i + second_probe_offset + UNROLL * Block::LANES < haystack.len() && !result { </del> <ins> while i + last_byte_offset + UNROLL * Block::LANES < haystack.len() && !result { </ins> let mut masks = [0u16; UNROLL]; for j in 0..UNROLL { masks[j] = test_chunk(i + j * Block::LANES);

} i += UNROLL * Block::LANES; } <del> while i + second_probe_offset + Block::LANES < haystack.len() && !result { </del> <ins> while i + last_byte_offset + Block::LANES < haystack.len() && !result { </ins> let mask = test_chunk(i); if mask != 0 { result |= check_mask(i, mask, result);

// This simply repeats the same procedure but as right-aligned chunk instead // of a left-aligned one. The last byte must be exactly flush with the string end so // we don't miss a single byte or read out of bounds. <del> let i = haystack.len() - second_probe_offset - Block::LANES; </del> <ins> let i = haystack.len() - last_byte_offset - Block::LANES; </ins> let mask = test_chunk(i); if mask != 0 { result |= check_mask(i, mask, result);

#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] // only called on x86 #[inline] unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool { <ins> debug_assert_eq!(x.len(), y.len()); </ins> // This function is adapted from // https://github.com/BurntSushi/memchr/blob/8037d11b4357b0f07be2bb66dc2659d9cf28ad32/src/memmem/util.rs#L32