libs-team: std::slice::from_raw_parts alternative that would accept a null pointer if len == 0 by returning an empty slice

Proposal

Problem statement

Currently, it’s not allowed to pass a NULL pointer to std::slice::from_raw_parts, but

I have a pointer that comes from a C function that can be either:

A) A non-NULL with a len > 0 B) A NULL with a len == 0

Solution sketch

It would be neat if it was possible to just write something like:

let values = unsafe { std::slice::from_raw_parts_or_empty(c_ptr_to_values, len) }; // Still panic if c_ptr_to_values == NULL and len > 0.
for value in values {
   // This can be skipped if values is an empty slice when c_ptr_to_values == NULL and len == 0.
   // Or values can be iterated when c_ptr_to_values != NULL and len > 0.
}

About this issue

  • Original URL
  • State: open
  • Created 4 months ago
  • Reactions: 10
  • Comments: 16 (11 by maintainers)

Most upvoted comments

so it not round-tripping with .as_mut_ptr() for the null case is certainly allowed 🙃

I suppose – but at the very least, it should not be solely based on len == 0 like https://github.com/rust-lang/libs-team/issues/350#issuecomment-1987137744. If given a non-null pointer, regardless of length, that should be preserved.

I feel really wary of having slice::from_raw_parts that would not round-trip with as_mut_ptr, but it seems less concerning with the _or_empty version to indicate that it’s not just the raw values.

This briefly came up in the libs-api meeting. We thought it’d probably be useful to do a perf run to see the impact a check in std::slice::from_raw_parts would have on rustc.

@cuviper Nice catch, indeed I didn’t think of that, I updated the code…

but currently std::slice::from_raw_parts(null(), 0) (not std::ptr::from_raw_parts) is undefined behavior according to the doc (&[T] must be non-null), so it not round-tripping with .as_mut_ptr() for the null case is certainly allowed 🙃

I don’t think we should be touching the existing functions simply because of how widely used they are in the ecosystem. Even adding a simple check there could have a large performance impact.

Pondering: is there a reasonable way we could have a takes-NonNull version of from_raw_parts (and the _mut one)? If so, that one could be the one without the check for null – after all, there’s a type proof it’s not null – and we could change the existing method to always check for null-and-zero-length, returning <&[_]>::default() in those cases.

I don’t know if that’s a good idea, though. I don’t know how to weight the tradeoff between fixing any broken unsafe code that’s trying to do this today vs the potential cost of either the extra extraneous check or people migrating.

Actually, maybe it’s completely fine, since if a parameter is ptr noundef nonnull, LLVM seems perfectly capable of removing the extra null check: https://rust.godbolt.org/z/PbY1recY3