[PATCH] D39245: [ADT] Shuffle containers before sorting to uncover non-deterministic behavior

Mandeep Singh Grang via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 24 09:55:20 PDT 2017


mgrang created this revision.
Herald added a subscriber: mgorny.

std::sort and array_pod_sort both use quicksort which is a non-stable sorting
algorithm. This means that the relative order of elements with the same key is
undefined. This patch is an attempt to uncover such scenarios. If LLVM is built
with the macro -DLLVM_SHUFFLE_BEFORE_SORT:BOOL=ON then we randomly shuffle
the container before sorting.

NOTE: To randomly shuffle before std::sort we may have to change all calls
to std::sort with llvm::sort.


Repository:
  rL LLVM

https://reviews.llvm.org/D39245

Files:
  cmake/modules/HandleLLVMOptions.cmake
  include/llvm/ADT/STLExtras.h
  include/llvm/Config/abi-breaking.h.cmake


Index: include/llvm/Config/abi-breaking.h.cmake
===================================================================
--- include/llvm/Config/abi-breaking.h.cmake
+++ include/llvm/Config/abi-breaking.h.cmake
@@ -18,6 +18,9 @@
 /* Define to enable reverse iteration of unordered llvm containers */
 #cmakedefine01 LLVM_ENABLE_REVERSE_ITERATION
 
+/* Define to enable shuffling of elements before sorting */
+#cmakedefine01 LLVM_ENABLE_SHUFFLE_BEFORE_SORT
+
 /* Allow selectively disabling link-time mismatch checking so that header-only
    ADT content from LLVM can be used without linking libSupport. */
 #if !LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING
Index: include/llvm/ADT/STLExtras.h
===================================================================
--- include/llvm/ADT/STLExtras.h
+++ include/llvm/ADT/STLExtras.h
@@ -32,6 +32,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/iterator.h"
 #include "llvm/ADT/iterator_range.h"
+#include "llvm/Config/abi-breaking.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
 
@@ -771,6 +772,9 @@
   // behavior with an empty sequence.
   auto NElts = End - Start;
   if (NElts <= 1) return;
+#if LLVM_ENABLE_SHUFFLE_BEFORE_SORT
+  std::random_shuffle(Start, End);
+#endif
   qsort(&*Start, NElts, sizeof(*Start), get_array_pod_sort_comparator(*Start));
 }
 
@@ -784,10 +788,30 @@
   // behavior with an empty sequence.
   auto NElts = End - Start;
   if (NElts <= 1) return;
+#if LLVM_ENABLE_SHUFFLE_BEFORE_SORT
+  std::random_shuffle(Start, End);
+#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.
+template <typename IteratorTy>
+void sort(IteratorTy Start, IteratorTy End) {
+#if LLVM_ENABLE_SHUFFLE_BEFORE_SORT
+  std::random_shuffle(Start, End);
+#endif
+  std::sort(Start, End);
+}
+
+template <typename IteratorTy, typename Compare>
+void sort(IteratorTy Start, IteratorTy End, Compare Comp) {
+#if LLVM_ENABLE_SHUFFLE_BEFORE_SORT
+  std::random_shuffle(Start, End);
+#endif
+  std::sort(Start, End, Comp);
+}
+
 //===----------------------------------------------------------------------===//
 //     Extra additions to <algorithm>
 //===----------------------------------------------------------------------===//
Index: cmake/modules/HandleLLVMOptions.cmake
===================================================================
--- cmake/modules/HandleLLVMOptions.cmake
+++ cmake/modules/HandleLLVMOptions.cmake
@@ -105,6 +105,10 @@
   set( LLVM_ENABLE_REVERSE_ITERATION 1 )
 endif()
 
+if( LLVM_SHUFFLE_BEFORE_SORT )
+  set( LLVM_ENABLE_SHUFFLE_BEFORE_SORT 1 )
+endif()
+
 if(WIN32)
   set(LLVM_HAVE_LINK_VERSION_SCRIPT 0)
   if(CYGWIN)


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D39245.120088.patch
Type: text/x-patch
Size: 2786 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20171024/8f99c12e/attachment.bin>


More information about the llvm-commits mailing list