| Index: testing/libfuzzer/fuzzers/re2_fuzzer.cc
|
| diff --git a/testing/libfuzzer/fuzzers/re2_fuzzer.cc b/testing/libfuzzer/fuzzers/re2_fuzzer.cc
|
| index 353aa7ef330f86aac8047ad0e4f40397a21c92e6..c59ce2ff0a07d83fab3ab1944c8674ec52c9cb5e 100644
|
| --- a/testing/libfuzzer/fuzzers/re2_fuzzer.cc
|
| +++ b/testing/libfuzzer/fuzzers/re2_fuzzer.cc
|
| @@ -1,87 +1,106 @@
|
| -// Copyright (c) 2016 The Chromium Authors. All rights reserved.
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +// Copyright 2016 The RE2 Authors. All Rights Reserved.
|
| +// Use of this source code is governed by a BSD-style
|
| +// license that can be found in the LICENSE file.
|
| +
|
| #include <stddef.h>
|
| #include <stdint.h>
|
|
|
| +#include <map>
|
| #include <string>
|
|
|
| #include "re2/re2.h"
|
| #include "util/logging.h"
|
|
|
| +using re2::StringPiece;
|
| using std::string;
|
|
|
| -void Test(const string& buffer, const string& pattern,
|
| - const RE2::Options& options) {
|
| +// NOT static, NOT signed.
|
| +uint8_t dummy = 0;
|
| +
|
| +void Test(StringPiece pattern, const RE2::Options& options, StringPiece text) {
|
| RE2 re(pattern, options);
|
| if (!re.ok())
|
| return;
|
|
|
| - string m1, m2;
|
| - int i1, i2;
|
| - double d1;
|
| -
|
| - if (re.NumberOfCapturingGroups() == 0) {
|
| - RE2::FullMatch(buffer, re);
|
| - RE2::PartialMatch(buffer, re);
|
| - } else if (re.NumberOfCapturingGroups() == 1) {
|
| - RE2::FullMatch(buffer, re, &m1);
|
| - RE2::PartialMatch(buffer, re, &i1);
|
| - } else if (re.NumberOfCapturingGroups() == 2) {
|
| - RE2::FullMatch(buffer, re, &i1, &i2);
|
| - RE2::PartialMatch(buffer, re, &m1, &m2);
|
| - }
|
| + // Don't waste time fuzzing high-fanout programs.
|
| + // (They can also cause bug reports due to fuzzer timeouts.)
|
| + std::map<int, int> histogram;
|
| + int fanout = re.ProgramFanout(&histogram);
|
| + if (fanout > 9)
|
| + return;
|
|
|
| - re2::StringPiece input(buffer);
|
| - RE2::Consume(&input, re, &m1);
|
| - RE2::FindAndConsume(&input, re, &d1);
|
| - string tmp1(buffer);
|
| - RE2::Replace(&tmp1, re, "zz");
|
| - string tmp2(buffer);
|
| - RE2::GlobalReplace(&tmp2, re, "xx");
|
| - RE2::QuoteMeta(re2::StringPiece(pattern));
|
| -}
|
| + StringPiece sp1, sp2, sp3, sp4;
|
| + string s1, s2, s3, s4;
|
| + int i1, i2, i3, i4;
|
| + double d1, d2, d3, d4;
|
|
|
| -// Entry point for LibFuzzer.
|
| -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
| - if (size < 1)
|
| - return 0;
|
| + RE2::FullMatch(text, re, &sp1, &sp2, &sp3, &sp4);
|
| + RE2::PartialMatch(text, re, &s1, &s2, &s3, &s4);
|
|
|
| - re2::FLAGS_minloglevel = 3;
|
| - RE2::Options options;
|
| + sp1 = sp2 = text;
|
| + RE2::Consume(&sp1, re, &i1, &i2, &i3, &i4);
|
| + RE2::FindAndConsume(&sp2, re, &d1, &d2, &d3, &d4);
|
|
|
| - size_t options_randomizer = 0;
|
| - for (size_t i = 0; i < size; i++)
|
| - options_randomizer += data[i];
|
| + s3 = s4 = text.ToString();
|
| + RE2::Replace(&s3, re, "");
|
| + RE2::GlobalReplace(&s4, re, "");
|
|
|
| - if (options_randomizer & 1)
|
| - options.set_encoding(RE2::Options::EncodingLatin1);
|
| -
|
| - options.set_posix_syntax(options_randomizer & 2);
|
| - options.set_longest_match(options_randomizer & 4);
|
| - options.set_literal(options_randomizer & 8);
|
| - options.set_never_nl(options_randomizer & 16);
|
| - options.set_dot_nl(options_randomizer & 32);
|
| - options.set_never_capture(options_randomizer & 64);
|
| - options.set_case_sensitive(options_randomizer & 128);
|
| - options.set_perl_classes(options_randomizer & 256);
|
| - options.set_word_boundary(options_randomizer & 512);
|
| - options.set_one_line(options_randomizer & 1024);
|
| + // Exercise some other API functionality.
|
| + dummy += re.NumberOfCapturingGroups();
|
| + dummy += RE2::QuoteMeta(pattern).size();
|
| +}
|
|
|
| - options.set_log_errors(false);
|
| +// Entry point for libFuzzer.
|
| +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
| + if (size == 0 || size > 1024)
|
| + return 0;
|
|
|
| - const char* data_input = reinterpret_cast<const char*>(data);
|
| - {
|
| - string pattern(data_input, size);
|
| - string buffer(data_input, size);
|
| - Test(buffer, pattern, options);
|
| + // The one-at-a-time hash by Bob Jenkins.
|
| + uint32_t hash = 0;
|
| + for (size_t i = 0; i < size; i++) {
|
| + hash += data[i];
|
| + hash += (hash << 10);
|
| + hash ^= (hash >> 6);
|
| }
|
| + hash += (hash << 3);
|
| + hash ^= (hash >> 11);
|
| + hash += (hash << 15);
|
|
|
| - if (size >= 3) {
|
| - string pattern(data_input, size / 3);
|
| - string buffer(data_input + size / 3, size - size / 3);
|
| - Test(buffer, pattern, options);
|
| + re2::FLAGS_minloglevel = 3;
|
| + RE2::Options options;
|
| + options.set_log_errors(false);
|
| + options.set_encoding(hash & 1 ? RE2::Options::EncodingLatin1
|
| + : RE2::Options::EncodingUTF8);
|
| + options.set_posix_syntax(hash & 2);
|
| + options.set_longest_match(hash & 4);
|
| + options.set_literal(hash & 8);
|
| + options.set_never_nl(hash & 16);
|
| + options.set_dot_nl(hash & 32);
|
| + options.set_never_capture(hash & 64);
|
| + options.set_case_sensitive(hash & 128);
|
| + options.set_perl_classes(hash & 256);
|
| + options.set_word_boundary(hash & 512);
|
| + options.set_one_line(hash & 1024);
|
| +
|
| + const char* ptr = reinterpret_cast<const char*>(data);
|
| + int len = static_cast<int>(size);
|
| +
|
| + StringPiece pattern(ptr, len);
|
| + StringPiece text(ptr, len);
|
| + Test(pattern, options, text);
|
| +
|
| + for (int i = 2; i <= 4; i++) {
|
| + if (len < i)
|
| + break;
|
| +
|
| + int frac = len / i;
|
| + pattern = StringPiece(ptr, frac);
|
| + text = StringPiece(ptr + frac, len - frac);
|
| + Test(pattern, options, text);
|
| }
|
|
|
| return 0;
|
|
|