#!/usr/bin/env python # Test case to demonstrate pyexpat crash under NetBSD. # This causes a segfault with 2.6.7 under both 5.99.47/amd64 and # 5.1_STABLE/i386. from __future__ import print_function import platform import sys import xml.parsers.expat def start_element(name, attrs): pass def end_element(name): pass def char_data(data): pass ep = None def instantiate_parser(): """Create an Expat parser instance (intended for re-use across multiple calls to its Parse() method) and attach generic delegate methods.""" global ep try: ep = xml.parsers.expat.ParserCreate() ep.StartElementHandler = start_element ep.EndElementHandler = end_element ep.CharacterDataHandler = char_data except xml.parsers.expat.ExpatError as error: print("An error occurred during Expat set-up. " \ + "Error ID: " + str(error.code) \ + ". Error message: " \ + xml.parsers.expat.ErrorString(error.code), file=sys.stderr) # We're not actually using this function since we'll crash before it # gets called... def destroy_parser(): """Invoke a final call to the Expat parser's Parse() method to pass the IsFinal value of True so it will destroy itself.""" global ep if ep != None: try: ep.Parse('', True) except xml.parsers.expat.ExpatError as error: print("An error occurred during XML parsing. " \ + "Error ID: " + str(error.code) \ + ". Error message: " \ + xml.parsers.expat.ErrorString(error.code), file=sys.stderr) finally: ep = None def parse_doc(input_string): """Accepts a string representing relevant data from an XML file and initiates the extraction of relevant data via proxy methods.""" global ep if ep == None: instantiate_parser() try: ep.Parse(input_string, False) except xml.parsers.expat.ExpatError as error: print("An error occurred during XML parsing. " \ + "Error ID: " + str(error.code) \ + ". Error message: " \ + xml.parsers.expat.ErrorString(error.code), file=sys.stderr) print("Line number:", ep.ErrorLineNumber, file=sys.stderr) small_test_file = \ """ 777 443> """ # 3,970,856 bytes is the exact minimum file (buffer growth) size that triggers # the segmentation fault in my NetBSD test environments. if platform.system() == 'NetBSD': data_size = 248174 # XXX Expand as necessary for other OSes... I haven't been able to get this to # crash on Mac OS X with any input size... else: data_size = 1 large_test_file = \ '' \ + "\n\n" \ + "1234\n" * data_size \ + '' if __name__ == "__main__": parse_doc(small_test_file) # Initial, successful parse parse_doc(small_test_file) # First triggering of a parser error parse_doc(large_test_file) # Subsequent parser error, with more data destroy_parser()