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

Switch builtins.sort to a custom stable PeekSort #12623

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

xokdvium
Copy link
Contributor

@xokdvium xokdvium commented Mar 9, 2025

Motivation

Unlike std::sort and std::stable_sort, this implementation
does not lead to out-of-bounds memory reads or other undefined
behavior when the predicate is not strict weak ordering.

This makes it possible to use this function in libexpr for
builtins.sort, where an incorrectly implemented comparator
in the user nix code currently can crash and burn the evaluator
by invoking C++ UB.

This prevents C++ level undefined behavior from affecting
the evaluator. Stdlib implementation details should not affect
eval, regardless of the build platform. Even erroneous usage
of builtins.sort should not make it possible to crash the
evaluator or produce results that depend on the host platform.

Context

#12106


Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

Unlike std::sort and std::stable_sort, this implementation
does not lead to out-of-bounds memory reads or other undefined
behavior when the predicate is not strict weak ordering.

This makes it possible to use this function in libexpr for
builtins.sort, where an incorrectly implemented comparator
in the user nix code currently can crash and burn the evaluator
by invoking C++ UB.
This prevents C++ level undefined behavior from affecting
the evaluator. Stdlib implementation details should not affect
eval, regardless of the build platform. Even erroneous usage
of `builtins.sort` should not make it possible to crash the
evaluator or produce results that depend on the host platform.
…16 elements

libstdc++'s std::stable_sort and new builtins.sort implementation
special-case ranges with length less than or equal to 16 and delegate
to insertionsort.

Having a larger e2e test would allow catching sort stability issues
at functional level as well.
@github-actions github-actions bot added the with-tests Issues related to testing. PRs with tests have some priority label Mar 9, 2025
@xokdvium xokdvium marked this pull request as ready for review March 9, 2025 21:49
comparator a b && comparator b c -> comparator a c
```

1. Irreflexivity
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to add that the relation must also be asymmetric.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if mentioning it here explicitly would be preferable. Irreflexivity together with transitivity already imply that the relation is asymmetric: a < b && b < a -> (a < a = false). Maybe including this in the doc is beneficial, even if it's somewhat redundant from the mathematics point of view?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW when I think about this stuff, I tend to start with a "total preorder" for <= (which is also a total order on equivalence classes for <=), and then define a total order from it.

Comment on lines +196 to +199
for (auto innerBegin = begin; innerBegin < innerEnd; ++innerBegin) {
ASSERT_LE(prevId, innerBegin->second);
prevId = innerBegin->second;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified with std::is_sorted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
with-tests Issues related to testing. PRs with tests have some priority
Projects
Status: To triage
Development

Successfully merging this pull request may close these issues.

2 participants