Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Un-unsafe the StableOrd trait #126326

Merged
merged 2 commits into from
Jun 25, 2024
Merged

Un-unsafe the StableOrd trait #126326

merged 2 commits into from
Jun 25, 2024

Conversation

eggyal
Copy link
Contributor

@eggyal eggyal commented Jun 12, 2024

Whilst incorrect implementations of this trait can cause miscompilation, they cannot cause memory unsafety in rustc.

Discussed on Zulip.

cc MCP 533, #105175, @michaelwoerister

r? @Nilstrieb

Whilst incorrect implementations of this trait can cause miscompilation,
they cannot cause memory unsafety in rustc.
@rustbot rustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) 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 Jun 12, 2024
@michaelwoerister
Copy link
Member

Yes, I agree that this shouldn't be unsafe. Implementing the trait has nothing to do with language invariants. @Nilstrieb was right all along 🙂

It would be nice though if we had some kind of #[rustc::triple_check_every_impl_of_this_trait] and #[rustc::this_impl_has_been_triple_checked] functionality.

@eggyal
Copy link
Contributor Author

eggyal commented Jun 13, 2024

Perhaps just add an associated THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED constant to the trait?

@eggyal
Copy link
Contributor Author

eggyal commented Jun 13, 2024

However none of these approaches prevent the type later being modified to then have fields that break the invariant.

Perhaps a more robust approach would be to define it as an auto-trait that is unimplemented for types that are unstable across compilations?

@Urgau
Copy link
Member

Urgau commented Jun 13, 2024

It would be nice though if we had some kind of #[rustc::triple_check_every_impl_of_this_trait] and #[rustc::this_impl_has_been_triple_checked] functionality.

This feels very similar to the proposed the clippy::dangerous attribute. I wish it were already merged and usable.

@michaelwoerister
Copy link
Member

[rustc::this_impl_has_been_triple_checked_for_transitive_hash_of_all_reachable_code(0x124159831948129481821948)] 😉

@michaelwoerister
Copy link
Member

Perhaps just add an associated THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED constant to the trait?

That seems as effective as marking as unsafe, at least 👍

@michaelwoerister
Copy link
Member

Perhaps a more robust approach would be to define it as an auto-trait that is unimplemented for types that are unstable across compilations?

If we can reliably define that set of types, that would be the best solution.

@michaelwoerister
Copy link
Member

However, we also have to take the implementation of Ord into account which can do whatever it wants.

@eggyal
Copy link
Contributor Author

eggyal commented Jun 13, 2024

I'll experiment.

@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 Jun 13, 2024
@eggyal
Copy link
Contributor Author

eggyal commented Jun 18, 2024

However, we also have to take the implementation of Ord into account which can do whatever it wants.

Indeed, for the current definition of StableOrd a StableAcrossCompilations auto-trait is neither sufficient (Ord might depend upon global state) nor necessary (Ord might ignore any "unstable" fields).

However, if the definition of StableOrd was narrowed to require that the Ord implementation be structural, we have some interesting options: StructuralPartialEq becomes necessary (though sadly not sufficient, as Ord could still rely on global state to determine the order of unequal values); and a(n as yet non-existent) StructuralPartialOrd analogue would be both sufficient and necessary, which would enable us to automate the whole shebang whilst statically enforcing the contract:

trait StructuralPartialOrd {} // implemented by derive(PartialOrd)
auto trait StableAcrossCompilations {} // negative impls TBD

trait StableOrd: StableAcrossCompilations + StructuralPartialOrd + Ord {}
impl<T: ?Sized + StableAcrossCompilations + StructuralPartialOrd + Ord> StableOrd for T {}

Types that are currently StableOrd but would cease to be so under this narrowed definition would instead have to implement StableCompare directly. So far as I can see, the only ones are Option<T>, PathBuf and Path.

Furthermore we could adjust the StableCompare trait so that (instead of it having a stable_cmp method that performs a "stable comparison") it has a fn stable_sort_key(&self) -> impl StableOrd method. This would guarantee that the ordering is stable even in these cases (provided that the returned key is derived only from local data).

As regards negative implementations of the StableAcrossCompilations auto-trait:

If we can reliably define that set of types, that would be the best solution.

My immediate thought is that negative implementations would have to be provided for raw pointers and rustc_index::Idx types (modulo some exceptions, e.g. ItemLocalId).


Questions:

  1. Do the risks justify this complexity?
  2. Is such a StructuralPartialOrd trait likely to be accepted into the standard library, even as perma-unstable, when there is (presently) no call for it outside of rustc? If not, might StructualPartialEq be an acceptable proxy on the basis that a type that derives PartialEq is unlikely to rely on global state in PartialOrd?
  3. Are there any other types that are unstable across compilations? Is this approach sufficiently reliable?
  4. I have ignored the CAN_USE_UNSTABLE_SORT constant, as all implementations are currently true: can we therefore remove it altogether?

@Noratrieb
Copy link
Member

i feel like this is overcomplicated it. keeping it as-is as a normal trait and maybe having a "I promise it's fine" const should be more than enough.

Added an associated `const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED`
to the `StableOrd` trait to ensure that implementors carefully consider
whether the trait's contract is upheld, as incorrect implementations can
cause miscompilations.
@eggyal
Copy link
Contributor Author

eggyal commented Jun 22, 2024

@rustbot ready

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

Feel free to r=me, unless @Nilstrieb has any further comments.

@Noratrieb
Copy link
Member

i don't!
@bors r=michaelwoerister

@bors
Copy link
Contributor

bors commented Jun 24, 2024

📌 Commit 0e73e70 has been approved by michaelwoerister

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 24, 2024
@michaelwoerister
Copy link
Member

Thanks for cleaning this up, @eggyal 🙂

compiler-errors added a commit to compiler-errors/rust that referenced this pull request Jun 25, 2024
…elwoerister

Un-unsafe the `StableOrd` trait

Whilst incorrect implementations of this trait can cause miscompilation, they cannot cause memory unsafety in rustc.

[Discussed on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Policy.20of.20.60unsafe.60.20within.20the.20compiler).

cc [MCP 533](rust-lang/compiler-team#533), rust-lang#105175, `@michaelwoerister`

r? `@Nilstrieb`
bors added a commit to rust-lang-ci/rust that referenced this pull request Jun 25, 2024
…mpiler-errors

Rollup of 9 pull requests

Successful merges:

 - rust-lang#126326 (Un-unsafe the `StableOrd` trait)
 - rust-lang#126618 (Mark assoc tys live only if the corresponding trait is live)
 - rust-lang#126724 (Fix a span in `parse_ty_bare_fn`.)
 - rust-lang#126746 (Deny `use<>` for RPITITs)
 - rust-lang#126868 (not use offset when there is not ends with brace)
 - rust-lang#126884 (Do not ICE when suggesting dereferencing closure arg)
 - rust-lang#126915 (Don't suggest awaiting in closure patterns)
 - rust-lang#126916 (Specify target specific linker for `riscv64gc-gnu` job)
 - rust-lang#126926 (Tweak a confusing comment in `create_match_candidates`)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors
Copy link
Contributor

bors commented Jun 25, 2024

⌛ Testing commit 0e73e70 with merge c290e9d...

@bors
Copy link
Contributor

bors commented Jun 25, 2024

☀️ Test successful - checks-actions
Approved by: michaelwoerister
Pushing c290e9d to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jun 25, 2024
@bors bors merged commit c290e9d into rust-lang:master Jun 25, 2024
7 checks passed
@rustbot rustbot added this to the 1.81.0 milestone Jun 25, 2024
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (c290e9d): comparison URL.

Overall result: ❌ regressions - no action needed

@rustbot label: -perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
3.0% [0.3%, 5.7%] 2
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results (primary 2.4%, secondary 6.0%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
2.4% [2.4%, 2.4%] 1
Regressions ❌
(secondary)
6.0% [4.5%, 8.2%] 3
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.4% [2.4%, 2.4%] 1

Cycles

Results (secondary 3.8%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
3.8% [3.8%, 3.8%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 692.703s -> 694.374s (0.24%)
Artifact size: 326.77 MiB -> 324.66 MiB (-0.64%)

@eggyal eggyal deleted the ununsafe-StableOrd branch July 2, 2024 06:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. 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.

7 participants