/ libxml2 / fuzz / libxml2_xml_saxparser_fuzzer.cc
libxml2_xml_saxparser_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/parserInternals.h"
 16  #include "libxml/xmlsave.h"
 17  
 18  extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
 19  
 20  static void errorCallback(void* ctx, const char* msg, ...) {
 21    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
 22    xmlErrorPtr error = xmlCtxtGetLastError(ctxt);
 23    if (error != NULL && error->level == XML_ERR_FATAL)
 24      xmlStopParser(ctxt);
 25  }
 26  
 27  static xmlSAXHandler xmlSAXHandlerStruct = {
 28    NULL, /* internalSubset */
 29    NULL, /* isStandalone */
 30    NULL, /* hasInternalSubset */
 31    NULL, /* hasExternalSubset */
 32    NULL, /* resolveEntity */
 33    NULL, /* getEntity */
 34    NULL, /* entityDecl */
 35    NULL, /* notationDecl */
 36    NULL, /* attributeDecl */
 37    NULL, /* elementDecl */
 38    NULL, /* unparsedEntityDecl */
 39    NULL, /* setDocumentLocator */
 40    NULL, /* startDocument */
 41    NULL, /* endDocument */
 42    NULL, /* startElement */
 43    NULL, /* endElement */
 44    NULL, /* reference */
 45    NULL, /* characters */
 46    NULL, /* ignorableWhitespace */
 47    NULL, /* processingInstruction */
 48    NULL, /* comment */
 49    NULL, /* xmlParserWarning */
 50    errorCallback, /* xmlParserError */
 51    NULL, /* xmlParserError */
 52    NULL, /* getParameterEntity */
 53    NULL, /* cdataBlock; */
 54    NULL, /* externalSubset; */
 55    XML_SAX2_MAGIC,
 56    NULL,
 57    NULL, /* startElementNs */
 58    NULL, /* endElementNs */
 59    NULL  /* xmlStructuredErrorFunc */
 60  };
 61  
 62  extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
 63    // Test default empty options value and some random combination.
 64    std::string data_string(reinterpret_cast<const char*>(data), size);
 65    const std::size_t data_hash = std::hash<std::string>()(data_string);
 66    const int max_option_value = std::numeric_limits<int>::max();
 67    const int random_option_value = data_hash % max_option_value;
 68    const int options[] = {0, random_option_value};
 69  
 70    for (const auto option_value : options) {
 71      // See testSAX() in xmllint.c.
 72      if (xmlParserInputBufferPtr inputBuffer = xmlParserInputBufferCreateMem((const char*)data, (int)size, XML_CHAR_ENCODING_NONE)) {
 73        if (xmlParserCtxtPtr ctxt = xmlNewParserCtxt()) {
 74          xmlCtxtUseOptions(ctxt, option_value | XML_PARSE_NOENT | XML_PARSE_NONET);
 75          xmlSAXHandlerPtr handler = &xmlSAXHandlerStruct;
 76          //XMLSAXHandlerSaver saver(ctxt, handler);
 77          xmlSAXHandlerPtr old_sax = ctxt->sax;
 78          ctxt->sax = handler;
 79          ctxt->userData = ctxt;
 80          if (xmlParserInputPtr inputStream = xmlNewIOInputStream(ctxt, inputBuffer, XML_CHAR_ENCODING_NONE)) {
 81            inputPush(ctxt, inputStream);
 82            xmlParseDocument(ctxt);
 83            if (xmlDocPtr doc = ctxt->myDoc) {
 84              ctxt->myDoc = nullptr;
 85  
 86              auto buf = xmlBufferCreate();
 87              assert(buf);
 88              auto ctxtSave = xmlSaveToBuffer(buf, NULL, 0);
 89              xmlSaveDoc(ctxtSave, doc);
 90              xmlSaveClose(ctxtSave);
 91  
 92              xmlFreeDoc(doc);
 93            }
 94          }
 95          ctxt->sax = old_sax;
 96          xmlFreeParserCtxt(ctxt);
 97        }
 98      }
 99    }
100  
101    return 0;
102  }