Skip to content

API soundness issue in join() implementation of [Borrow<str>] #80335

Description

@qwaz

A weird Borrow implementation that returns a different result for each call can create a string with uninitialized bytes with join() implementation of [Borrow<str>] type.

The problem is in join_generic_copy function.

  1. The borrow result is first used for the length calculation.

    // compute the exact total length of the joined Vec
    // if the `len` calculation overflows, we'll panic
    // we would have run out of memory anyway and the rest of the function requires
    // the entire Vec pre-allocated for safety
    let len = sep_len
    .checked_mul(iter.len())
    .and_then(|n| {
    slice.iter().map(|s| s.borrow().as_ref().len()).try_fold(n, usize::checked_add)
    })
    .expect("attempt to join into collection with len > usize::MAX");

  2. Then, inside spezialize_for_lengths macro, the user-provided slice is borrowed again and the content is copied.

    // arbitrary non-zero size fallback
    for s in iter {
    copy_slice_and_advance!(target, sep_bytes);
    copy_slice_and_advance!(target, s.borrow().as_ref());
    }

  3. Finally, the length of the slice is set to the length calculated in step 1.

    result.set_len(len);

Playground link, which demonstrates creating a non-UTF-8 string by only using safe Rust.

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

    C-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