Skip to content

CString does not preserve capacity #74794

Open
@kotauskas

Description

@kotauskas

Simplest repro:

use std::ffi::CString;
let vec = Vec::with_capacity(87);
let cstring = CString::new(vec);
let vec = cstring.into_bytes();
assert_eq!(vec.capacity(), 87);

I expected CString to behave like String, preserving capacity from the Vec it was created. Instead, the CString implementation shrinks-to-fit and stores a boxed slice, which is then converted back into Vec in into_bytes/into_bytes_with_nul, giving back as much capacity as there were elements, i.e. 1 which is the nul terminator.

I vaguely understand the reasoning for this — when &CStr becomes a narrow pointer, Box<CStr> would be a narrow pointer too, meaning that CString also will; in such a case, if CString was a Vec instead, it would be three pointers in size (pointer, size, capacity). This means, however, that there's no reason to use CString instead of Box<CStr>, making it essentially useless.

In other words, the only reason for String/OsString/CString to exist in parallel with Box<str>/Box<OsStr>/Box<CStr> is to provide the same safety guarantees for the contents while also providing Vec-like functionality (growing/shrinking and spare capacity). In reality, CString does not provide those at all, much like OsString (though it'd be considerably more complex to implement push/pop for OsString on Windows even if it's a Vec, since that'd mean that encoding and decoding the underlying WTF-8 would be required).

As an initial effort, OsString and CString can be transformed into Vecs transparently to their public APIs. Then, the Vec API can be integrated via the usual RFC process.

Meta

rustc --version --verbose:

rustc 1.46.0-nightly (3503f565e 2020-07-02)
binary: rustc
commit-hash: 3503f565e1fb7296983757d2716346f48a4a262b
commit-date: 2020-07-02
host: x86_64-unknown-linux-gnu
release: 1.46.0-nightly
LLVM version: 10.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-libs-apiRelevant to the library API 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