Skip to content

Challenges 20/21/22/10: "Assumption 3" is now a safety requirement of unsafe trait Pattern (rust-lang/rust#165681) #753

Open

Description

@feliperodri

Summary

rust-lang#165681 (merged 2026-11-10) made Pattern an unsafe trait, with this
new requirement on into_searcher:

The returned searcher must search the provided haystack. In particular,
Searcher::haystack() must return the same string slice passed to this method.

This is the property that Assumption 3 of Challenges 20 and 21 lets solutions assume
("all the Searchers ... are created by the into_searcher(_, haystack) with haystack being a
valid UTF-8 string"). Before the change, nothing guaranteed it. Pattern was a safe trait,
so safe code could return a valid std Searcher built for a different string, and std
consumers then applied its indices to the original string. That led to UB from safe code:

Scope: the assumption covered real UB in functions these challenges list

On nightly-2026-10-23, which is this repo's current toolchain, I checked every
str/String consumer of into_searcher(self) with a safe Pattern returning a
CharSearcher for another string. I used Kani on the real std, then confirmed each case
natively with AddressSanitizer. 17 APIs had UB:

Affected API Challenge listing it
split_once, rsplit_once, strip_prefix, strip_suffix, trim_start_matches, trim_end_matches, trim_matches, replace (slow path), replacen 20 and 21 list the str methods built on str::pattern (e.g. split_once, strip_prefix)
split, rsplit, splitn, rsplitn, split_terminator, rsplit_terminator, split_inclusive (the last piece is sliced from matcher.haystack() using self.len()) 22: SplitInternal::get_end, next, next_inclusive, …
String::remove_matches (writes out of bounds, then set_len > capacity) 10: remove_matches (unbounded)

Not affected: matches, rmatches, match_indices, rmatch_indices, find, rfind.

So, before rust-lang#165681:

  • A proof of Challenges 20/21 under Assumption 3 was sound only relative to an assumption
    that safe code could break.
  • Challenge 22's assumption 2 ("safety and functional correctness of all functions in
    pattern.rs") and Challenge 10's remove_matches relied on it implicitly.

After rust-lang#165681 the assumption is part of Pattern's safety contract, which is the right
place for it.

Suggested changes

  1. Challenge text (20, 21; maybe 22 and 10). Replace Assumption 3 with a reference to
    Pattern's safety requirement (into_searcher returns a searcher for the given
    haystack). Challenge 22's assumption 2 and Challenge 10's remove_matches entry could
    say explicitly that they depend on it.
  2. Toolchain bump. The repo is pinned to nightly-2026-10-23, which is before Add safety requirements for Pattern and Searcher rust-lang/rust#165681.
    After a bump past 2026-11-10, impl Pattern for … in harnesses fails with E0200 and
    needs unsafe impl. Open PRs that define a safe Pattern impl:
  3. Harness modelling. A model Pattern must now uphold the into_searcher
    guarantee (haystack() is the passed slice). The PRs above already bind the searcher
    to the passed haystack, so this only needs to be stated as the reason the model is valid.

Proposed solutions for the affected challenges

Challenge 20 (#277): char Searchers in str::pattern

Challenge 21 (#278): StrSearcher in str::pattern

Challenge 22 (#279): str iter functions

Challenge 10 (#61): String (covers remove_matches)

Reproducer (pre-rust-lang#165681 toolchain)

#![feature(pattern, string_remove_matches)]
#![forbid(unsafe_code)]
use std::str::pattern::{CharSearcher, Pattern};

struct WrongHaystack;
impl Pattern for WrongHaystack {
    type Searcher<'a> = CharSearcher<'a>;
    fn into_searcher(self, _haystack: &str) -> CharSearcher<'_> {
        'X'.into_searcher("aaaaaXaX")
    }
}

fn main() {
    let mut s = String::from("a");
    s.remove_matches(WrongHaystack); // nightly-2026-10-23: len = usize::MAX, capacity = 1, heap corruption
}

On nightly-2026-11-11 (9c5648833) this no longer compiles:
error[E0200]: the trait Pattern requires an unsafe impl declaration.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions