Skip to content

String::replace_range is unsound #81138

Closed
@KamilaBorowska

Description

@KamilaBorowska

It's possible to use String::replace_range to create invalid strings containing broken Unicode. This happens because replace_range checks range bounds twice - first time to check parameter validity and second time for actually doing the splice.

use std::cell::Cell;
use std::ops::{Bound, RangeBounds};
use std::str;

struct EvilRange(Cell<bool>);

impl RangeBounds<usize> for EvilRange {
    fn start_bound(&self) -> Bound<&usize> {
        Bound::Included(if self.0.get() {
            &1
        } else {
            self.0.set(true);
            &0
        })
    }
    fn end_bound(&self) -> Bound<&usize> {
        Bound::Unbounded
    }
}

fn main() {
    let mut s = String::from("🦀");
    s.replace_range(EvilRange(Cell::new(false)), "");
    println!("{:?}", str::from_utf8(s.as_bytes()));
}

This will print Utf8Error showing that a string is not valid UTF-8.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-UnicodeArea: UnicodeC-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-highHigh priorityT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions