Do not dereference in slice_from_raw_parts postcondition - #627
Open
tautschnig wants to merge 1 commit into
Open
Conversation
NonNull::slice_from_raw_parts is a safe function with no validity
requirements on `data`: per its documentation, it is safe to construct
the pointer, and only its use is subject to safety conditions. Its
postcondition however evaluated `unsafe { result.as_ref() }.len()`,
creating a reference to the pointed-to memory just to read the slice
length - undefined behavior when `data` is dangling or misaligned, and
a failing check when the contract is evaluated in such a context.
This surfaces with dependency contracts asserted (the Kani default
since model-checking/kani#3802):
ptr::non_null::verify::non_null_check_as_uninit_slice_mut constructs,
legitimately, a NonNull slice pointer whose span may exceed the backing
allocation; evaluating slice_from_raw_parts' postcondition then fails
with "misaligned pointer to reference cast" / "dereference failure:
pointer invalid" inside NonNull::as_ref. CI currently masks this with
--no-assert-contracts.
Read the length from the wide-pointer metadata via NonNull::len
instead, which involves no dereference (and no unsafe code) and is the
property the clause is about in the first place.
The dereferencing clause was introduced with the original contracts in
07318df ("Contracts and harnesses for `dangling`, `from_raw_parts`,
`slice_from_raw_parts`, `to_raw_parts` in NonNull" model-checking#127).
Verified (Kani 152c6a8c + CBMC 6.10.0): non_null_check_as_uninit_slice_mut,
non_null_check_slice_from_raw_parts, non_null_check_as_uninit_slice and
non_null_check_len pass both with and without --no-assert-contracts
(the first previously failed with contracts asserted).
Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Updates the verification postcondition for NonNull::slice_from_raw_parts to avoid dereferencing potentially dangling/misaligned pointers during contract evaluation, aligning the contract with the function’s documented safety behavior.
Changes:
- Replace the postcondition’s
unsafe { result.as_ref() }.len()withresult.len()to read slice length from wide-pointer metadata without creating a reference. - Add an explanatory comment documenting why dereferencing in the postcondition is UB for valid (but non-dereferenceable) inputs to this safe constructor.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
NonNull::slice_from_raw_partsis a safe function with no validity requirements ondata: per its documentation, it is safe to construct the pointer, and only its use is subject to safety conditions. Its postcondition however evaluatedunsafe { result.as_ref() }.len(), creating a reference to the pointed-to memory just to read the slice length — undefined behavior whendatais dangling or misaligned, and a failing check when the contract is evaluated in such a context.This surfaces with dependency contracts asserted (the Kani default since model-checking/kani#3802):
ptr::non_null::verify::non_null_check_as_uninit_slice_mutconstructs, legitimately, aNonNullslice pointer whose span may exceed the backing allocation; evaluatingslice_from_raw_parts' postcondition then fails with "misaligned pointer to reference cast" / "dereference failure: pointer invalid" insideNonNull::as_ref. CI currently masks this with--no-assert-contracts.This PR reads the length from the wide-pointer metadata via
NonNull::leninstead, which involves no dereference (and no unsafe code) and is the property the clause is about in the first place.Blame: the dereferencing clause dates to the original contracts in 07318df (#127).
Verified with Kani 152c6a8c + CBMC 6.10.0:
non_null_check_as_uninit_slice_mut,non_null_check_slice_from_raw_parts,non_null_check_as_uninit_sliceandnon_null_check_lenpass both with and without--no-assert-contracts(the first previously failed with contracts asserted — the last remaining failure of that kind known on the 125-harness sample after #622, #623, #624, #625, #626).By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.