/ libxml2 / fuzz / libxml2_xml_pushparser_fuzzer.cc
libxml2_xml_pushparser_fuzzer.cc
 1  // Copyright 2015 The Chromium Authors. All rights reserved.
 2  // Copyright 2017 Apple Inc. All rights reserved.
 3  // Use of this source code is governed by a BSD-style license that can be
 4  // found in the LICENSE file.
 5  
 6  #include <cassert>
 7  #include <cstddef>
 8  #include <cstdint>
 9  
10  #include <functional>
11  #include <limits>
12  #include <string>
13  
14  #include "libxml/parser.h"
15  #include "libxml/xmlsave.h"
16  
17  extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
18  
19  static void ignore (void* ctx, const char* msg, ...) {
20    // Error handler to avoid spam of error messages from libxml parser.
21  }
22  
23  extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
24    xmlSetGenericErrorFunc(NULL, &ignore);
25  
26    assert(size < std::numeric_limits<int>::max());
27    int intSize = static_cast<int>(size);
28  
29    // Test default empty options value and some random combination.
30    std::string data_string(reinterpret_cast<const char*>(data), size);
31    const std::size_t data_hash = std::hash<std::string>()(data_string);
32    const int max_option_value = std::numeric_limits<int>::max();
33    const int random_option_value = data_hash % max_option_value;
34    const int options[] = {0, random_option_value};
35  
36    int initialChunkSize = std::min<int>(4, intSize);
37    int chunkSize = std::max<int>(100, std::min<int>(data_hash % 1024, intSize));
38  
39    for (const auto option_value : options) {
40      if (auto ctxt = xmlCreatePushParserCtxt(NULL, NULL, (const char *)data, initialChunkSize, "noname.xml")) {
41        xmlCtxtUseOptions(ctxt, option_value | XML_PARSE_NONET);
42        int cur = initialChunkSize;
43        do {
44          if (cur + chunkSize >= size) {
45            xmlParseChunk(ctxt, (const char *)data + cur, intSize - cur, 1);
46            break;
47          } else {
48            xmlParseChunk(ctxt, (const char *)data + cur, chunkSize, 0);
49            cur += chunkSize;
50          }
51        } while (cur < size);
52        auto doc = ctxt->myDoc;
53        xmlFreeParserCtxt(ctxt);
54  
55        auto buf = xmlBufferCreate();
56        assert(buf);
57        auto ctxtSave = xmlSaveToBuffer(buf, NULL, 0);
58        xmlSaveDoc(ctxtSave, doc);
59        xmlSaveClose(ctxtSave);
60        xmlFreeDoc(doc);
61        xmlBufferFree(buf);
62      }
63    }
64  
65    return 0;
66  }