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 }