#!/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()