| // 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. | 
 |  | 
 | #include <stdint.h> | 
 |  | 
 | #include "tools/gn/input_file.h" | 
 | #include "tools/gn/parser.h" | 
 | #include "tools/gn/source_file.h" | 
 | #include "tools/gn/tokenizer.h" | 
 |  | 
 | namespace { | 
 |  | 
 | enum { kMaxContentDepth = 256, kMaxDodgy = 256 }; | 
 |  | 
 | // Some auto generated input is too unreasonable for fuzzing GN. | 
 | // We see stack overflow when the parser hits really deeply "nested" input. | 
 | // (I.E.: certain input that causes nested parsing function calls). | 
 | // | 
 | // Abstract max limits are undesirable in the release GN code, so some sanity | 
 | // checks in the fuzzer to prevent stack overflow are done here. | 
 | // - 1) Too many opening bracket, paren, or brace in a row. | 
 | // - 2) Too many '!', '<' or '>' operators in a row. | 
 | bool SanityCheckContent(const std::vector<Token>& tokens) { | 
 |   int depth = 0; | 
 |   int dodgy_count = 0; | 
 |   for (const auto& token : tokens) { | 
 |     switch (token.type()) { | 
 |       case Token::LEFT_PAREN: | 
 |       case Token::LEFT_BRACKET: | 
 |       case Token::LEFT_BRACE: | 
 |         ++depth; | 
 |         break; | 
 |       case Token::RIGHT_PAREN: | 
 |       case Token::RIGHT_BRACKET: | 
 |       case Token::RIGHT_BRACE: | 
 |         --depth; | 
 |         break; | 
 |       case Token::BANG: | 
 |       case Token::LESS_THAN: | 
 |       case Token::GREATER_THAN: | 
 |         ++dodgy_count; | 
 |         break; | 
 |       default: | 
 |         break; | 
 |     } | 
 |     // Bail out as soon as a boundary is hit, inside the loop. | 
 |     if (depth >= kMaxContentDepth || dodgy_count >= kMaxDodgy) | 
 |       return false; | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) { | 
 |   SourceFile source; | 
 |   InputFile input(source); | 
 |   input.SetContents(std::string(reinterpret_cast<const char*>(data), size)); | 
 |  | 
 |   Err err; | 
 |   std::vector<Token> tokens = Tokenizer::Tokenize(&input, &err); | 
 |   if (!SanityCheckContent(tokens)) | 
 |     return 0; | 
 |  | 
 |   if (!err.has_error()) | 
 |     Parser::Parse(tokens, &err); | 
 |  | 
 |   return 0; | 
 | } |