OLD | NEW |
(Empty) | |
| 1 //===- NaClSimpleRecordFuzzer.cpp - Simple fuzzer of bitcode --------------===// |
| 2 // |
| 3 // The LLVM Compiler Infrastructure |
| 4 // |
| 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. |
| 7 // |
| 8 //===----------------------------------------------------------------------===// |
| 9 // |
| 10 // This file implements a simple fuzzer for a list of PNaCl bitcode records. |
| 11 // |
| 12 //===----------------------------------------------------------------------===// |
| 13 |
| 14 #include "llvm/ADT/STLExtras.h" |
| 15 #include "llvm/Bitcode/NaCl/NaClFuzz.h" |
| 16 #include "llvm/Support/Format.h" |
| 17 |
| 18 #include <array> |
| 19 #include <cmath> |
| 20 #include <cstdlib> |
| 21 #include <map> |
| 22 #include <set> |
| 23 |
| 24 |
| 25 using namespace llvm; |
| 26 using namespace naclfuzz; |
| 27 |
| 28 namespace { |
| 29 |
| 30 // Counts the number of times each value in a range [0..N) is used (based |
| 31 // on the number of calls to method increment()). |
| 32 class DistCounter { |
| 33 DistCounter(const DistCounter&) = delete; |
| 34 void operator=(const DistCounter&) = delete; |
| 35 public: |
| 36 explicit DistCounter(size_t DistSize) |
| 37 : Dist(DistSize, 0), Total(0) {} |
| 38 |
| 39 // Increments the count for the given value |
| 40 size_t increment(size_t Value) { |
| 41 ++Dist[Value]; |
| 42 ++Total; |
| 43 return Value; |
| 44 } |
| 45 |
| 46 // Returns the end of the range being checked. |
| 47 size_t size() const { |
| 48 return Dist.size(); |
| 49 } |
| 50 |
| 51 // Returns the number of times value was incremented. |
| 52 size_t operator[](size_t Value) const { |
| 53 return Dist[Value]; |
| 54 } |
| 55 |
| 56 // Retrns the number of times any value in the distribution was |
| 57 // incremented. |
| 58 size_t getTotal() const { |
| 59 return Total; |
| 60 } |
| 61 private: |
| 62 // The number of times each value was incremented. |
| 63 std::vector<size_t> Dist; |
| 64 // The total number of times any value was incremented. |
| 65 size_t Total; |
| 66 }; |
| 67 |
| 68 // Model weights when randomly choosing values. |
| 69 typedef unsigned WeightType; |
| 70 |
| 71 // Associates weights with values. Used to generate weighted |
| 72 // distributions (see class WeightedDistribution below). |
| 73 template<typename T> |
| 74 struct WeightedValue { |
| 75 T Value; |
| 76 WeightType Weight; |
| 77 }; |
| 78 |
| 79 // Weighted distribution for a set of values in [0..DistSize). |
| 80 template<typename T> |
| 81 class WeightedDistribution { |
| 82 WeightedDistribution(const WeightedDistribution&) = delete; |
| 83 void operator=(const WeightedDistribution&) = delete; |
| 84 public: |
| 85 typedef const WeightedValue<T> *const_iterator; |
| 86 |
| 87 WeightedDistribution(const WeightedValue<T> Dist[], |
| 88 size_t DistSize, |
| 89 RandomNumberGenerator &Generator) |
| 90 : Dist(Dist), DistSize(DistSize), TotalWeight(0), Generator(Generator) { |
| 91 for (size_t i = 0; i < DistSize; ++i) |
| 92 TotalWeight += Dist[i].Weight; |
| 93 } |
| 94 |
| 95 virtual ~WeightedDistribution() {} |
| 96 |
| 97 /// Returns the number of weighted values in the distribution. |
| 98 size_t size() const { |
| 99 return DistSize; |
| 100 } |
| 101 |
| 102 /// Returns const iterator at beginning of weighted distribution. |
| 103 const_iterator begin() const { |
| 104 return Dist; |
| 105 } |
| 106 |
| 107 /// Returns const iterator at end of weighted distribution. |
| 108 const_iterator end() const { |
| 109 return Dist + DistSize; |
| 110 } |
| 111 |
| 112 /// Randomly chooses a weighted value in the distribution, based on |
| 113 /// the weights of the distrubution. |
| 114 virtual const WeightedValue<T> &choose() { |
| 115 return Dist[chooseIndex()]; |
| 116 } |
| 117 |
| 118 /// Returns the total weight associated with the distribution. |
| 119 size_t getTotalWeight() const { |
| 120 return TotalWeight; |
| 121 } |
| 122 |
| 123 protected: |
| 124 // The weighted values defining the distribution. |
| 125 const WeightedValue<T> *Dist; |
| 126 // The number of weighed values. |
| 127 size_t DistSize; |
| 128 // The total weight of the distribution (sum of weights in weighted values). |
| 129 size_t TotalWeight; |
| 130 // The random number generator to use. |
| 131 RandomNumberGenerator &Generator; |
| 132 |
| 133 // Randomly chooses an index of a weighed value in the distribution, |
| 134 // based on the weights of the distribution. |
| 135 size_t chooseIndex() { |
| 136 /// TODO(kschimpf) Speed this up? |
| 137 WeightType WeightedSum = Generator.chooseInRange(TotalWeight); |
| 138 assert(WeightedSum < TotalWeight); |
| 139 for (size_t Choice = 0; Choice < DistSize; ++Choice) { |
| 140 WeightType NextWeight = Dist[Choice].Weight; |
| 141 if (WeightedSum < NextWeight) |
| 142 return Choice; |
| 143 WeightedSum -= NextWeight; |
| 144 } |
| 145 llvm_unreachable("no index for WeightedDistribution.chooseIndex()"); |
| 146 } |
| 147 }; |
| 148 |
| 149 // Defines a range [min..max]. |
| 150 template<typename T> |
| 151 struct RangeType { |
| 152 T min; |
| 153 T max; |
| 154 }; |
| 155 |
| 156 // Weighted distribution of a set of value ranges. |
| 157 template<typename T> |
| 158 class WeightedRangeDistribution : public WeightedDistribution<RangeType<T>> { |
| 159 WeightedRangeDistribution(const WeightedRangeDistribution<T>&) = delete; |
| 160 void operator=(const WeightedRangeDistribution<T>&) = delete; |
| 161 public: |
| 162 WeightedRangeDistribution(const WeightedValue<RangeType<T>> Dist[], |
| 163 size_t DistSize, |
| 164 RandomNumberGenerator &Generator) |
| 165 : WeightedDistribution<RangeType<T>>(Dist, DistSize, Generator) {} |
| 166 |
| 167 // Choose a value from one of the value ranges. |
| 168 T chooseValue() { |
| 169 const RangeType<T> Range = this->choose().Value; |
| 170 return Range.min + |
| 171 this->Generator.chooseInRange(Range.max - Range.min + 1); |
| 172 } |
| 173 }; |
| 174 |
| 175 /// Weighted distribution with a counter, capturing the distribution |
| 176 /// of random choices for each weighted value. |
| 177 template<typename T> |
| 178 class CountedWeightedDistribution : public WeightedDistribution<T> { |
| 179 CountedWeightedDistribution(const CountedWeightedDistribution&) = delete; |
| 180 void operator=(const CountedWeightedDistribution&) = delete; |
| 181 public: |
| 182 CountedWeightedDistribution(const WeightedValue<T> Dist[], |
| 183 size_t DistSize, |
| 184 RandomNumberGenerator &Generator) |
| 185 : WeightedDistribution<T>(Dist, DistSize, Generator), Counter(DistSize) {} |
| 186 |
| 187 const WeightedValue<T> &choose() final { |
| 188 return this->Dist[Counter.increment( |
| 189 WeightedDistribution<T>::chooseIndex())]; |
| 190 } |
| 191 |
| 192 /// Returns the number of times the Index-th weighted value was |
| 193 /// chosen. |
| 194 size_t getChooseCount(size_t Index) const { |
| 195 return Counter[Index]; |
| 196 } |
| 197 |
| 198 /// Returns the total number of times method choose was called. |
| 199 size_t getTotalChooseCount() const { |
| 200 return Counter.getTotal(); |
| 201 } |
| 202 |
| 203 private: |
| 204 DistCounter Counter; |
| 205 }; |
| 206 |
| 207 #define ARRAY(array) array, array_lengthof(array) |
| 208 |
| 209 // Weighted distribution used to select edit actions. |
| 210 const WeightedValue<RecordFuzzer::EditAction> ActionDist[] = { |
| 211 {RecordFuzzer::InsertRecord, 3}, |
| 212 {RecordFuzzer::MutateRecord, 5}, |
| 213 {RecordFuzzer::RemoveRecord, 1}, |
| 214 {RecordFuzzer::ReplaceRecord, 1}, |
| 215 {RecordFuzzer::SwapRecord, 1} |
| 216 }; |
| 217 |
| 218 // Type of values in bitcode records. |
| 219 typedef uint64_t ValueType; |
| 220 |
| 221 // Weighted ranges for non-negative values in records. |
| 222 const WeightedValue<RangeType<ValueType>> PosValueDist[] = { |
| 223 {{0, 6}, 100}, |
| 224 {{7, 20}, 50}, |
| 225 {{21, 40}, 10}, |
| 226 {{41, 100}, 2}, |
| 227 {{101, 4096}, 1} |
| 228 }; |
| 229 |
| 230 // Distribution used to decide when use negative values in records. |
| 231 WeightedValue<bool> NegValueDist[] = { |
| 232 {true, 1}, // i.e. make value negative. |
| 233 {false, 100} // i.e. leave value positive. |
| 234 }; |
| 235 |
| 236 // Range distribution for records sizes (must be greater than 0). |
| 237 const WeightedValue<RangeType<size_t>> RecordSizeDist[] = { |
| 238 {{1, 3}, 1000}, |
| 239 {{4, 7}, 100}, |
| 240 {{7, 100}, 1} |
| 241 }; |
| 242 |
| 243 // Defines valid record codes. |
| 244 typedef unsigned RecordCodeType; |
| 245 |
| 246 // Special code to signify adding random other record codes. |
| 247 static const RecordCodeType OtherRecordCode = 575757575; |
| 248 |
| 249 // List of record codes we can generate. The weights are based |
| 250 // on record counts in pnacl-llc.pexe, using how many thousand of |
| 251 // each record code appeared (or 1 if less than 1 thousand). |
| 252 WeightedValue<RecordCodeType> RecordCodeDist[] = { |
| 253 {naclbitc::BLOCKINFO_CODE_SETBID, 1}, |
| 254 {naclbitc::MODULE_CODE_VERSION, 1}, |
| 255 {naclbitc::MODULE_CODE_FUNCTION, 7}, |
| 256 {naclbitc::TYPE_CODE_NUMENTRY, 1}, |
| 257 {naclbitc::TYPE_CODE_VOID, 1}, |
| 258 {naclbitc::TYPE_CODE_FLOAT, 1}, |
| 259 {naclbitc::TYPE_CODE_DOUBLE, 1}, |
| 260 {naclbitc::TYPE_CODE_INTEGER, 1}, |
| 261 {naclbitc::TYPE_CODE_VECTOR, 1}, |
| 262 {naclbitc::TYPE_CODE_FUNCTION, 1}, |
| 263 {naclbitc::VST_CODE_ENTRY, 1}, |
| 264 {naclbitc::VST_CODE_BBENTRY, 1}, |
| 265 {naclbitc::CST_CODE_SETTYPE, 15}, |
| 266 {naclbitc::CST_CODE_UNDEF, 1}, |
| 267 {naclbitc::CST_CODE_INTEGER, 115}, |
| 268 {naclbitc::CST_CODE_FLOAT, 1}, |
| 269 {naclbitc::GLOBALVAR_VAR, 14}, |
| 270 {naclbitc::GLOBALVAR_COMPOUND, 1}, |
| 271 {naclbitc::GLOBALVAR_ZEROFILL, 2}, |
| 272 {naclbitc::GLOBALVAR_DATA, 18}, |
| 273 {naclbitc::GLOBALVAR_RELOC, 20}, |
| 274 {naclbitc::GLOBALVAR_COUNT, 1}, |
| 275 {naclbitc::FUNC_CODE_DECLAREBLOCKS, 6}, |
| 276 {naclbitc::FUNC_CODE_INST_BINOP, 402}, |
| 277 {naclbitc::FUNC_CODE_INST_CAST, 61}, |
| 278 {naclbitc::FUNC_CODE_INST_EXTRACTELT, 1}, |
| 279 {naclbitc::FUNC_CODE_INST_INSERTELT, 1}, |
| 280 {naclbitc::FUNC_CODE_INST_RET, 7}, |
| 281 {naclbitc::FUNC_CODE_INST_BR, 223}, |
| 282 {naclbitc::FUNC_CODE_INST_SWITCH, 7}, |
| 283 {naclbitc::FUNC_CODE_INST_UNREACHABLE, 1}, |
| 284 {naclbitc::FUNC_CODE_INST_PHI, 84}, |
| 285 {naclbitc::FUNC_CODE_INST_ALLOCA, 34}, |
| 286 {naclbitc::FUNC_CODE_INST_LOAD, 225}, |
| 287 {naclbitc::FUNC_CODE_INST_STORE, 461}, |
| 288 {naclbitc::FUNC_CODE_INST_CMP2, 140}, |
| 289 {naclbitc::FUNC_CODE_INST_VSELECT, 10}, |
| 290 {naclbitc::FUNC_CODE_INST_CALL, 80}, |
| 291 {naclbitc::FUNC_CODE_INST_FORWARDTYPEREF, 36}, |
| 292 {naclbitc::FUNC_CODE_INST_CALL_INDIRECT, 5}, |
| 293 {naclbitc::BLK_CODE_ENTER, 1}, |
| 294 {naclbitc::BLK_CODE_EXIT, 1}, |
| 295 {naclbitc::BLK_CODE_DEFINE_ABBREV, 1}, |
| 296 {OtherRecordCode, 1} |
| 297 }; |
| 298 |
| 299 // *Warning* The current implementation does not work on empty bitcode |
| 300 // record lists. |
| 301 class SimpleRecordFuzzer : public RecordFuzzer { |
| 302 public: |
| 303 SimpleRecordFuzzer(NaClMungedBitcode &Bitcode, |
| 304 RandomNumberGenerator &Generator) |
| 305 : RecordFuzzer(Bitcode, Generator), |
| 306 RecordCounter(Bitcode.getBaseRecords().size()), |
| 307 ActionWeight(ARRAY(ActionDist), Generator), |
| 308 RecordSizeWeight(ARRAY(RecordSizeDist), Generator), |
| 309 PosValueWeight(ARRAY(PosValueDist), Generator), |
| 310 NegValueWeight(ARRAY(NegValueDist), Generator), |
| 311 RecordCodeWeight(ARRAY(RecordCodeDist), Generator) { |
| 312 |
| 313 assert(!Bitcode.getBaseRecords().empty() |
| 314 && "Can't fuzz empty list of records"); |
| 315 |
| 316 for (const auto &RecordCode : RecordCodeWeight) |
| 317 UsedRecordCodes.insert(RecordCode.Value); |
| 318 } |
| 319 |
| 320 ~SimpleRecordFuzzer() final; |
| 321 |
| 322 bool fuzz(unsigned Count, unsigned Base) final; |
| 323 |
| 324 void showRecordDistribution(raw_ostream &Out) const final; |
| 325 |
| 326 void showEditDistribution(raw_ostream &Out) const final; |
| 327 |
| 328 private: |
| 329 // Count how many edits are applied to each record in the bitcode. |
| 330 DistCounter RecordCounter; |
| 331 // Distribution used to randomly choose edit actions. |
| 332 CountedWeightedDistribution<RecordFuzzer::EditAction> ActionWeight; |
| 333 // Distribution used to randomly choose the size of created records. |
| 334 WeightedRangeDistribution<size_t> RecordSizeWeight; |
| 335 // Distribution used to randomly choose positive values for records. |
| 336 WeightedRangeDistribution<ValueType> PosValueWeight; |
| 337 // Distribution of value sign used to randomly choose value for records. |
| 338 WeightedDistribution<bool> NegValueWeight; |
| 339 // Distribution used to choose record codes for records. |
| 340 WeightedDistribution<RecordCodeType> RecordCodeWeight; |
| 341 // Filter to make sure the "other" choice for record codes will not |
| 342 // choose any other record code in RecordCodeWeight. |
| 343 std::set<size_t> UsedRecordCodes; |
| 344 |
| 345 // Randomly choose an edit action. |
| 346 RecordFuzzer::EditAction chooseAction() { |
| 347 return ActionWeight.choose().Value; |
| 348 } |
| 349 |
| 350 // Randomly choose a record index from the list of records to edit. |
| 351 size_t chooseRecordIndex() { |
| 352 return RecordCounter.increment( |
| 353 Generator.chooseInRange(Bitcode.getBaseRecords().size())); |
| 354 } |
| 355 |
| 356 // Randomly choose a record code. |
| 357 RecordCodeType chooseRecordCode() { |
| 358 RecordCodeType Code = RecordCodeWeight.choose().Value; |
| 359 if (Code != OtherRecordCode) |
| 360 return Code; |
| 361 Code = Generator.chooseInRange(UINT_MAX); |
| 362 while (UsedRecordCodes.count(Code)) // don't use predefined values. |
| 363 ++Code; |
| 364 return Code; |
| 365 } |
| 366 |
| 367 // Randomly choose a positive value for use in a record. |
| 368 ValueType choosePositiveValue() { |
| 369 return PosValueWeight.chooseValue(); |
| 370 } |
| 371 |
| 372 // Randomly choose a positive/negative value for use in a record. |
| 373 ValueType chooseValue() { |
| 374 ValueType Value = choosePositiveValue(); |
| 375 if (NegValueWeight.choose().Value) { |
| 376 // Use two's complement negation. |
| 377 Value = ~Value + 1; |
| 378 } |
| 379 return Value; |
| 380 } |
| 381 |
| 382 // Randomly fill in a record with record values. |
| 383 void chooseRecordValues(NaClBitcodeAbbrevRecord &Record) { |
| 384 Record.Abbrev = naclbitc::UNABBREV_RECORD; |
| 385 Record.Code = chooseRecordCode(); |
| 386 Record.Values.clear(); |
| 387 size_t NumValues = RecordSizeWeight.chooseValue(); |
| 388 for (size_t i = 0; i < NumValues; ++i) { |
| 389 Record.Values.push_back(chooseValue()); |
| 390 } |
| 391 } |
| 392 |
| 393 // Apply the given edit action to a random record. |
| 394 void applyAction(EditAction Action); |
| 395 |
| 396 // Randomly mutate a record. |
| 397 void mutateRecord(NaClBitcodeAbbrevRecord &Record) { |
| 398 // TODO(kschimpf) Do something smarter than just changing a value |
| 399 // in the record. |
| 400 size_t Index = Generator.chooseInRange(Record.Values.size() + 1); |
| 401 if (Index == 0) |
| 402 Record.Code = chooseRecordCode(); |
| 403 else |
| 404 Record.Values[Index - 1] = chooseValue(); |
| 405 } |
| 406 }; |
| 407 |
| 408 SimpleRecordFuzzer::~SimpleRecordFuzzer() {} |
| 409 |
| 410 bool SimpleRecordFuzzer::fuzz(unsigned Count, unsigned Base) { |
| 411 // TODO(kschimpf): Add some randomness in the number of actions selected. |
| 412 clear(); |
| 413 size_t NumRecords = Bitcode.getBaseRecords().size(); |
| 414 size_t NumActions = NumRecords * Count / Base; |
| 415 if (NumActions == 0) |
| 416 NumActions = 1; |
| 417 for (size_t i = 0; i < NumActions; ++i) |
| 418 applyAction(chooseAction()); |
| 419 return true; |
| 420 } |
| 421 |
| 422 void SimpleRecordFuzzer::applyAction(EditAction Action) { |
| 423 size_t Index = chooseRecordIndex(); |
| 424 switch(Action) { |
| 425 case InsertRecord: { |
| 426 NaClBitcodeAbbrevRecord Record; |
| 427 chooseRecordValues(Record); |
| 428 if (Generator.chooseInRange(2)) |
| 429 Bitcode.addBefore(Index, Record); |
| 430 else |
| 431 Bitcode.addAfter(Index, Record); |
| 432 return; |
| 433 } |
| 434 case RemoveRecord: |
| 435 Bitcode.remove(Index); |
| 436 return; |
| 437 case ReplaceRecord: { |
| 438 NaClBitcodeAbbrevRecord Record; |
| 439 chooseRecordValues(Record); |
| 440 Bitcode.replace(Index, Record); |
| 441 return; |
| 442 } |
| 443 case MutateRecord: { |
| 444 NaClBitcodeAbbrevRecord Copy(*Bitcode.getBaseRecords()[Index]); |
| 445 mutateRecord(Copy); |
| 446 Bitcode.replace(Index, Copy); |
| 447 return; |
| 448 } |
| 449 case SwapRecord: { |
| 450 size_t Index2 = chooseRecordIndex(); |
| 451 Bitcode.replace(Index, *Bitcode.getBaseRecords()[Index2]); |
| 452 Bitcode.replace(Index2, *Bitcode.getBaseRecords()[Index]); |
| 453 return; |
| 454 } |
| 455 } |
| 456 } |
| 457 |
| 458 // Returns corresponding percentage defined by Count/Total, in a form |
| 459 // that can be printed to a raw_ostream. |
| 460 format_object<float> percentage(size_t Count, size_t Total) { |
| 461 float percent = Total == 0.0 ? 0.0 : 100.0 * Count / Total; |
| 462 return format("%1.0f", nearbyintf(percent)); |
| 463 } |
| 464 |
| 465 void SimpleRecordFuzzer::showRecordDistribution(raw_ostream &Out) const { |
| 466 Out << "Edit Record Distribution (Total: " << RecordCounter.getTotal() |
| 467 << "):\n"; |
| 468 size_t Total = RecordCounter.getTotal(); |
| 469 for (size_t i = 0; i < Bitcode.getBaseRecords().size(); ++i) { |
| 470 size_t Count = RecordCounter[i]; |
| 471 Out << " " << format("%zd", i) << ": " |
| 472 << Count << " (" << percentage(Count, Total) << "%)\n"; |
| 473 } |
| 474 } |
| 475 |
| 476 void SimpleRecordFuzzer::showEditDistribution(raw_ostream &Out) const { |
| 477 size_t TotalWeight = ActionWeight.getTotalWeight(); |
| 478 size_t TotalCount = ActionWeight.getTotalChooseCount(); |
| 479 Out << "Edit Action Distribution(Total: " << TotalCount << "):\n"; |
| 480 size_t ActionIndex = 0; |
| 481 for (const auto &Action : ActionWeight) { |
| 482 size_t ActionCount = ActionWeight.getChooseCount(ActionIndex); |
| 483 Out << " " << actionName(Action.Value) << " - Wanted: " |
| 484 << percentage(Action.Weight, TotalWeight) << "%, Applied: " |
| 485 << ActionCount << " (" << percentage(ActionCount, TotalCount) |
| 486 << "%)\n"; |
| 487 ++ActionIndex; |
| 488 } |
| 489 } |
| 490 |
| 491 } // end of anonymous namespace |
| 492 |
| 493 namespace naclfuzz { |
| 494 |
| 495 RecordFuzzer *RecordFuzzer::createSimpleRecordFuzzer( |
| 496 NaClMungedBitcode &Bitcode, |
| 497 RandomNumberGenerator &Generator) { |
| 498 return new SimpleRecordFuzzer(Bitcode, Generator); |
| 499 } |
| 500 |
| 501 } // end of namespace naclfuzz |
OLD | NEW |