[PATCH] D21218: [LibFuzzer] Avoid using std::random_swap() due to platform differences and implement our own version.

Dan Liew via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 9 22:22:10 PDT 2016


delcypher created this revision.
delcypher added reviewers: kcc, aizatsky.
delcypher added subscribers: kcc, aizatsky, zaks.anna, kubabrecka, dcoughlin, llvm-commits.

[LibFuzzer] Avoid using std::random_swap() due to platform differences
and implement our own version.

It turns out that the behavior of std::random_swap is different between
libstdc++ and libcxx (even with the same random number source).
Therefore if we want consistent behavior between platforms we have to
use our own implementation.

This change (plus a change to the number of iterations of the Mutator in
the test required for the particular shuffle implementation used) fixes
the ``FuzzerMutate.ShuffleBytes2`` unit test on OSX.

I have verified that for the above unittest identical mutations are
now generated on both Linux and on OSX.


http://reviews.llvm.org/D21218

Files:
  lib/Fuzzer/FuzzerInternal.h
  lib/Fuzzer/FuzzerLoop.cpp
  lib/Fuzzer/FuzzerMutate.cpp
  lib/Fuzzer/test/FuzzerUnittest.cpp

Index: lib/Fuzzer/test/FuzzerUnittest.cpp
===================================================================
--- lib/Fuzzer/test/FuzzerUnittest.cpp
+++ lib/Fuzzer/test/FuzzerUnittest.cpp
@@ -259,7 +259,7 @@
   TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 16);
 }
 TEST(FuzzerMutate, ShuffleBytes2) {
-  TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 19);
+  TestShuffleBytes(&MutationDispatcher::Mutate, 566171);
 }
 
 void TestAddWordFromDictionary(Mutator M, int NumIter) {
Index: lib/Fuzzer/FuzzerMutate.cpp
===================================================================
--- lib/Fuzzer/FuzzerMutate.cpp
+++ lib/Fuzzer/FuzzerMutate.cpp
@@ -96,8 +96,7 @@
       Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
   size_t ShuffleStart = Rand(Size - ShuffleAmount);
   assert(ShuffleStart + ShuffleAmount <= Size);
-  std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
-                      Rand);
+  Rand.Shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount);
   return Size;
 }
 
Index: lib/Fuzzer/FuzzerLoop.cpp
===================================================================
--- lib/Fuzzer/FuzzerLoop.cpp
+++ lib/Fuzzer/FuzzerLoop.cpp
@@ -321,7 +321,7 @@
 }
 
 void Fuzzer::ShuffleCorpus(UnitVector *V) {
-  std::random_shuffle(V->begin(), V->end(), MD.GetRand());
+  MD.GetRand().Shuffle(V->begin(), V->end());
   if (Options.PreferSmall)
     std::stable_sort(V->begin(), V->end(), [](const Unit &A, const Unit &B) {
       return A.size() < B.size();
Index: lib/Fuzzer/FuzzerInternal.h
===================================================================
--- lib/Fuzzer/FuzzerInternal.h
+++ lib/Fuzzer/FuzzerInternal.h
@@ -137,6 +137,22 @@
   size_t RandBool() { return Rand() % 2; }
   size_t operator()(size_t n) { return n ? Rand() % n : 0; }
   std::mt19937 &Get_mt19937() { return R; }
+  // Shuffle data in the range [First, End)
+  //
+  // We do not use std::random_shuffle() here because its
+  // behavior is not consistent across different platforms.
+  //
+  // The algorithm used here will pick a permutation at
+  // random where every permutation has equal probability
+  // (provided the random source is uniformly distributed).
+  template<typename RndAccessIt>
+  void Shuffle(RndAccessIt First, RndAccessIt End) {
+    typename std::iterator_traits<RndAccessIt>::difference_type Offset, N;
+    N = End - First;
+    for (Offset = 0; Offset < N; ++Offset) {
+      std::swap(First[Offset], First[Offset + (*this)(N - Offset)]);
+    }
+  }
  private:
   std::mt19937 R;
 };


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D21218.60310.patch
Type: text/x-patch
Size: 2581 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160610/d9e53b0a/attachment.bin>


More information about the llvm-commits mailing list