Skip to content

Conversation

Zalathar
Copy link
Contributor

The existing implementation of LLVMRustCreateRangeAttribute has a theoretical soundness bug.

It delegates to LLVMCreateConstantRangeAttribute, which divides NumBits by 64 to determine how long the LowerWords/UpperWords slices are. Therefore, if NumBits > 128, the code will think that the slices have three or more elements, even though the Rust-side code only supplies two valid elements.

(I assume that this can't actually happen in practice, but because the CreateRangeAttribute wrapper function is safe, this still isn't ideal.)

This PR therefore avoids LLVMCreateConstantRangeAttribute entirely, and instead passes each range endpoint as two separate u64 values, which can be reassembled without relying on NumBits.

@rustbot
Copy link
Collaborator

rustbot commented Aug 25, 2025

r? @SparrowLii

rustbot has assigned @SparrowLii.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 25, 2025
@Zalathar
Copy link
Contributor Author

Zalathar commented Aug 25, 2025

Implementation of LLVM's LLVMCreateConstantRangeAttribute for reference:

https://github.com/llvm/llvm-project/blob/ad7bb1cc45a253d873198b9143fbe9c1e5d97aa5/llvm/lib/IR/Core.cpp#L194-L206

Notice that NumWords = divideCeil(NumBits, 64) is used as the length of the LowerWords/UpperWords slices, which does not necessarily match the length=2 array pointers that we actually pass.

@nikic
Copy link
Contributor

nikic commented Aug 25, 2025

Wouldn't it make more sense to assert that the number of bits is <= 128? Your new implementation (in a hypothetical world where WrappingRange can represent more than 128 bits) would also be wrong, just in a different way.

@Zalathar
Copy link
Contributor Author

I suppose that's true. It would no longer be UB, but it would still be a bug.

I'm still not fond of delegating to LLVMRustCreateRangeAttribute, because the precondition we have to uphold is rather non-obvious. And I think passing a few u64 scalars is preferable to passing pointers (with or without an explicit length), but I'm not sure how others feel about that.

@nikic
Copy link
Contributor

nikic commented Aug 25, 2025

I'm still not fond of delegating to LLVMRustCreateRangeAttribute, because the precondition we have to uphold is rather non-obvious. And I think passing a few u64 scalars is preferable to passing pointers (with or without an explicit length), but I'm not sure how others feel about that.

My thinking here was that we ideally wouldn't need LLVMRustCreateRangeAttribute at all, and directly use LLVMCreateConstantRangeAttribute instead. The only reason we don't do this right now is to pass Attribute::Range, which we could also fetch via the C API. So this change moves us further away from using the "vanilla" C API, which I'd generally consider undesirable.

@Zalathar
Copy link
Contributor Author

Hmm, I see.

I had mostly not considered moving towards LLVM-C for attribute kinds, because the documentation implies that looking up attribute kinds via the C API is even less stable than just using the C++ API, which made it seem pretty unattractive. But I don't know how accurate that is in reality.

@Zalathar
Copy link
Contributor Author

I'll prepare a narrower PR that just fixes the soundness hole with an assert (and some docs), which will leave the rest of the overhaul as a separate matter.

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 26, 2025
@rustbot
Copy link
Collaborator

rustbot commented Aug 26, 2025

Reminder, once the PR becomes ready for a review, use @rustbot ready.

GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request Aug 26, 2025
cg_llvm: Assert that LLVM range-attribute values don't exceed 128 bits

The underlying implementation of `LLVMCreateConstantRangeAttribute` assumes that each of `LowerWords` and `UpperWords` points to enough u64 values to define an integer of the specified bit-length, and will encounter UB if that is not the case.

Our safe wrapper function always passes pointers to `[u64; 2]` arrays, regardless of the bit-length specified. That's fine in practice, because scalar primitives never exceed 128 bits, but it is technically a soundness hole in a safe function.

We can close the soundness hole by explicitly asserting `size_bits <= 128`. This is effectively just a stricter version of the existing check that the value must be small enough to fit in `c_uint`.

---

This is a narrower version of the fix in rust-lang#145846.
rust-timer added a commit that referenced this pull request Aug 26, 2025
Rollup merge of #145867 - Zalathar:range-attr, r=nikic

cg_llvm: Assert that LLVM range-attribute values don't exceed 128 bits

The underlying implementation of `LLVMCreateConstantRangeAttribute` assumes that each of `LowerWords` and `UpperWords` points to enough u64 values to define an integer of the specified bit-length, and will encounter UB if that is not the case.

Our safe wrapper function always passes pointers to `[u64; 2]` arrays, regardless of the bit-length specified. That's fine in practice, because scalar primitives never exceed 128 bits, but it is technically a soundness hole in a safe function.

We can close the soundness hole by explicitly asserting `size_bits <= 128`. This is effectively just a stricter version of the existing check that the value must be small enough to fit in `c_uint`.

---

This is a narrower version of the fix in #145846.
@bors
Copy link
Collaborator

bors commented Aug 26, 2025

☔ The latest upstream changes (presumably #145886) made this pull request unmergeable. Please resolve the merge conflicts.

@Zalathar Zalathar closed this Aug 26, 2025
@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Aug 26, 2025
@Zalathar Zalathar deleted the llvm-range-attr branch August 26, 2025 23:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants