Skip to content

Tracking Issue for pointer_is_aligned_to #96284

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
5 of 7 tasks
Gankra opened this issue Apr 21, 2022 · 12 comments
Open
5 of 7 tasks

Tracking Issue for pointer_is_aligned_to #96284

Gankra opened this issue Apr 21, 2022 · 12 comments
Labels
C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@Gankra
Copy link
Contributor

Gankra commented Apr 21, 2022

Feature gate: #![feature(pointer_is_aligned)]
Feature gate: #![feature(pointer_is_aligned_to)]

This is a tracking issue for ptr.is_aligned() and ptr.is_aligned_to(alignment).

Public API

impl *const T {
    // feature gate `pointer_is_aligned` was stabilized
    // pub fn is_aligned(self) -> bool where T: Sized;
    // feature gate `pointer_is_aligned_to`
    pub fn is_aligned_to(self, align: usize) -> bool;
}
// ... and the same for` *mut T`

impl <T: ?Sized> NonNull<T> {
    pub const fn is_aligned_to(self, align: usize) -> bool;
}

Steps / History

pointer_is_aligned:

pointer_is_aligned_to:

Unresolved Questions

  • Should is_aligned_to require a power of two or should it be more flexible? (currently panics)
@Gankra Gankra added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC labels Apr 21, 2022
@scottmcm
Copy link
Member

For the unresolved question: another option might be to expose https://stdrs.dev/nightly/x86_64-unknown-linux-gnu/core/mem/valid_align/struct.ValidAlign.html and use it as the parameter type.

@WaffleLapkin
Copy link
Member

WaffleLapkin commented Sep 4, 2022

I want to propose to stabilize these methods! (can someone open an fcp?)

Stabilization report

Implementation History

API Summary

impl *const T {
    pub fn is_aligned(self) -> bool where T: Sized;
    pub fn is_aligned_to(self, align: usize) -> bool;
}

// ... and the same for` *mut T`

Experience Report

#100820 and #100823 refactored some std code into using these methods simplifying the code.

These methods were long requested (see for example #56304) and seem to be quite nice to use. They also may have slightly better codegen, compared to naive % align implementation.

@scottmcm
Copy link
Member

scottmcm commented Sep 6, 2022

I think the unresolved question needs an answer, not just a mention.

As I brought up earlier, I think it'd be really nice to have a type for valid alignments. The other two options are both unfortunate, IMHO: needing to assert!(align.is_power_of_two()) in something that would otherwise be a trivial bit of code, or just going 🤷 and returning garbage if the input isn't a power of two.

@WaffleLapkin
Copy link
Member

So, our options for resolving the unresolved question:

  1. Leave as-is, assert!(align.is_power_of_two())
    • Pros: notifies users of about invalid usages
    • Cons: in some cases adds an additional check/panic
  2. Make behavior is case of !align.is_power_of_two() implementation defined (non-sensible result, debug_assert!, etc)
    • Pros: no performance penalty, ever
    • Cons: does not notify users about invalid usages
  3. Introduce a type that holds always valid alignment
    • Pros: impossible to use incorrectly, such type can improve other APIs as well
    • Cons: bigger API surface, users need to move to new APIs (align_of2::<T>() -> Align?...), given an usize (e.g. from an external library) you need a trailing_zeros call to convert back

I'm leaning towards 2, but that's just me 🤷

@tyler274
Copy link

tyler274 commented Sep 14, 2022

Could these methods be made const fns ?

@WaffleLapkin
Copy link
Member

@tyler274 they can't, CTFE engine (compile time function execution) does not (necessarily) have a notion of "address" of a pointer. Since you can't take the address (e.g. it's UB to transmute::<*const (), usize>() in CTFE) you also can't check if it's divisible by something.

@scottmcm
Copy link
Member

scottmcm commented Sep 16, 2022

given an usize (e.g. from an external library) you need a trailing_zeros call to convert back

That's assuming it would be stored as log_2(align), but that's not necessary. In fact, the type that Layout uses internally today stores it as the power of two -- since that's convenient for things like the usual &(align-1) trick. So using a usize from an external library would be a "free" Alignment::new_unchecked call (if you can trust that other library).

EDIT: I opened an ACP to add an Alignment newtype to core: rust-lang/libs-team#108

@m-ou-se m-ou-se added the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Sep 20, 2022
@m-ou-se
Copy link
Member

m-ou-se commented Sep 20, 2022

Question from the libs-api meeting: How often would one use is_aligned_to given that is_aligned exists? (Or maybe a is_aligned_for::<T>() might suffice for most cases?)

How often does one want to check a calculated alignment rather than a constant alignment? With e.g. .is_aligned_to(16), the check would be optimized away, making the usize argument fine. Using a separate Alignment type would only add extra verbosity.

@m-ou-se m-ou-se removed the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Sep 20, 2022
@WaffleLapkin
Copy link
Member

Status update: I originally planned to use grep.app or an alternative to gather stats about "is aligned" checks in the wild. But... I did not have enough courage to finish the work and now I simply do not have the capacity for that.

If anyone wants to take this from here (and answer t-libs-api questions in the above post) — feel free to.

@MaxVerevkin
Copy link

Or maybe a is_aligned_for::<T>() might suffice for most cases?

Can is_aligned() be stabilized before is_aligned_to()? Especially because it can be used as cast::<T>().is_aligned().

@saethlin
Copy link
Member

Question from the libs-api meeting: How often would one use is_aligned_to given that is_aligned exists? (Or maybe a is_aligned_for::<T>() might suffice for most cases?)

The standard library currently only uses is_aligned_to to implement is_aligned.

I searched grep.app as Waffle suggests above, and I only found these callers that could not easily port to .is_aligned() or .cast().is_aligned().

https://github.com/jamwaffles/linuxcnc-hal-rs/blob/0aac97869278fd90a7e3857226cb8ebd4ce89123/linuxcnc-hal/src/hal_pin/hal_pin.rs#L33-L45
https://github.com/SFBdragon/talc/blob/deb93cf518da25f9eb61cd7154c68f0e3f6be90f/src/talck.rs#L132-L138
https://github.com/twizzler-operating-system/twizzler/blob/4ec5a30d1348d0af395dc018d951658a2c00434a/src/kernel/src/memory/pagetables/table.rs#L47-L50

But also, those 3 projects are not even using the unstable is_aligned_to.

At this time, I do not think that the is_aligned_to method is suitably motivated.

Gankra added a commit to Gankra/rust that referenced this issue Mar 3, 2024
Per rust-lang#96284 (comment)
this API is a mess and is regarded as insufficiently motivated. Removing
it from the public API is potentially the only blocker on stabilizing
its pleasant brother .is_aligned().

I initially just deleted it completely but it's since become Heavily Used
for the purposes of assert_unsafe_precondition, and there's clearly
Some Stuff going on with that API that I have no interest in poking.
Gankra added a commit to Gankra/rust that referenced this issue Mar 3, 2024
Per rust-lang#96284 (comment)
this API is a mess and is regarded as insufficiently motivated. Removing
it from the public API is potentially the only blocker on stabilizing
its pleasant brother .is_aligned().

I initially just deleted it completely but it's since become Heavily Used
for the purposes of assert_unsafe_precondition, and there's clearly
Some Stuff going on with that API that I have no interest in poking.
Gankra added a commit to Gankra/rust that referenced this issue Mar 3, 2024
Per rust-lang#96284 (comment)
this API is a mess and is regarded as insufficiently motivated. Removing
it from the public API is potentially the only blocker on stabilizing
its pleasant brother .is_aligned().

I initially just deleted it completely but it's since become Heavily Used
for the purposes of assert_unsafe_precondition, and there's clearly
Some Stuff going on with that API that I have no interest in poking.
Gankra added a commit to Gankra/rust that referenced this issue Mar 3, 2024
Per rust-lang#96284 (comment)
this API is a mess and is regarded as insufficiently motivated. Removing
it from the public API is potentially the only blocker on stabilizing
its pleasant brother .is_aligned().

I initially just deleted it completely but it's since become Heavily Used
for the purposes of assert_unsafe_precondition, and there's clearly
Some Stuff going on with that API that I have no interest in poking.
Gankra added a commit to Gankra/rust that referenced this issue Mar 3, 2024
Per rust-lang#96284 (comment)
this API is a mess and is regarded as insufficiently motivated. Removing
it from the public API is potentially the only blocker on stabilizing
its pleasant brother .is_aligned().

I initially just deleted it completely but it's since become Heavily Used
for the purposes of assert_unsafe_precondition, and there's clearly
Some Stuff going on with that API that I have no interest in poking.
@Gankra
Copy link
Contributor Author

Gankra commented Mar 3, 2024

I propose we split the feature into two and stabilize the perfectly inoffensive ptr.is_aligned(), which handles 95% of usecases.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants