Skip to content

Commit

Permalink
[ADT] Shuffle containers before sorting to uncover non-deterministic …
Browse files Browse the repository at this point in the history
…behavior

Summary:
std::sort and array_pod_sort both use non-stable sorting algorithms.
This means that the relative order of elements with the same key is
undefined. This patch is an attempt to uncover such scenarios by
randomly shuffling all containers before sorting, if EXPENSIVE_CHECKS
is enabled.

Here's the bugzilla for this: https://bugs.llvm.org/show_bug.cgi?id=35135

Reviewers: dblaikie, dexonsmith, chandlerc, efriedma, RKSimon

Reviewed By: RKSimon

Subscribers: fhahn, davide, RKSimon, vsk, mgorny, llvm-commits

Differential Revision: https://reviews.llvm.org/D39245

llvm-svn: 327219
  • Loading branch information
Mandeep Singh Grang committed Mar 10, 2018
1 parent ff1248f commit 5a3d47f
Showing 1 changed file with 32 additions and 0 deletions.
32 changes: 32 additions & 0 deletions llvm/include/llvm/ADT/STLExtras.h
Expand Up @@ -36,6 +36,10 @@
#include <type_traits>
#include <utility>

#ifdef EXPENSIVE_CHECKS
#include <random> // for std::mt19937
#endif

namespace llvm {

// Only used by compiler if both template types are the same. Useful when
Expand Down Expand Up @@ -762,6 +766,10 @@ inline void array_pod_sort(IteratorTy Start, IteratorTy End) {
// behavior with an empty sequence.
auto NElts = End - Start;
if (NElts <= 1) return;
#ifdef EXPENSIVE_CHECKS
std::mt19937 Generator(std::random_device{}());
std::shuffle(Start, End, Generator);
#endif
qsort(&*Start, NElts, sizeof(*Start), get_array_pod_sort_comparator(*Start));
}

Expand All @@ -775,10 +783,34 @@ inline void array_pod_sort(
// behavior with an empty sequence.
auto NElts = End - Start;
if (NElts <= 1) return;
#ifdef EXPENSIVE_CHECKS
std::mt19937 Generator(std::random_device{}());
std::shuffle(Start, End, Generator);
#endif
qsort(&*Start, NElts, sizeof(*Start),
reinterpret_cast<int (*)(const void *, const void *)>(Compare));
}

// Provide wrappers to std::sort which shuffle the elements before sorting
// to help uncover non-deterministic behavior (PR35135).
template <typename IteratorTy>
inline void sort(IteratorTy Start, IteratorTy End) {
#ifdef EXPENSIVE_CHECKS
std::mt19937 Generator(std::random_device{}());
std::shuffle(Start, End, Generator);
#endif
std::sort(Start, End);
}

template <typename IteratorTy, typename Compare>
inline void sort(IteratorTy Start, IteratorTy End, Compare Comp) {
#ifdef EXPENSIVE_CHECKS
std::mt19937 Generator(std::random_device{}());
std::shuffle(Start, End, Generator);
#endif
std::sort(Start, End, Comp);
}

//===----------------------------------------------------------------------===//
// Extra additions to <algorithm>
//===----------------------------------------------------------------------===//
Expand Down

0 comments on commit 5a3d47f

Please sign in to comment.