Skip to content

Commit 6744a09

Browse files
committed
fix ticket 903782: initialise document dict for HTML parsing in iterparse to prevent segfaults on cleanup
--HG-- extra : transplant_source : G%BE%D7Pe%05%03%B8C%24%10%25I%7D%834%5B%E2%C9%02
1 parent 0334afc commit 6744a09

4 files changed

Lines changed: 38 additions & 2 deletions

File tree

CHANGES.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,18 @@ Bugs fixed
3232
a descendant combinator. For example, "div> .foo" was parsed the same as
3333
"div>* .foo" instead of "div>.foo". Patch by Simon Sapin.
3434

35-
* lxml.html.diff no longer raises an exception when hitting
36-
'img' tags without 'src' attribute.
35+
* Fixed a crash when using ``iterparse()`` for HTML parsing and
36+
requesting start events.
3737

3838
* Fixed parsing of more selectors in cssselect. Whitespace before
3939
pseudo-elements and pseudo-classes is significant as it is a
4040
descendant combinator.
4141
"E :pseudo" should parse the same as "E \*:pseudo", not "E:pseudo".
4242
Patch by Simon Sapin.
4343

44+
* lxml.html.diff no longer raises an exception when hitting
45+
'img' tags without 'src' attribute.
46+
4447
Other changes
4548
--------------
4649

src/lxml/iterparse.pxi

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ cdef class _IterparseContext(_ParserContext):
6464
cdef xmlparser.endElementNsSAX2Func _origSaxEnd
6565
cdef xmlparser.startElementSAXFunc _origSaxStartNoNs
6666
cdef xmlparser.endElementSAXFunc _origSaxEndNoNs
67+
cdef xmlparser.startDocumentSAXFunc _origSaxStartDocument
6768
cdef xmlparser.commentSAXFunc _origSaxComment
6869
cdef xmlparser.processingInstructionSAXFunc _origSaxPI
6970
cdef _Element _root
@@ -88,6 +89,8 @@ cdef class _IterparseContext(_ParserContext):
8889
cdef xmlparser.xmlSAXHandler* sax
8990
_ParserContext._initParserContext(self, c_ctxt)
9091
sax = c_ctxt.sax
92+
self._origSaxStartDocument = sax.startDocument
93+
sax.startDocument = _iterparseSaxStartDocument
9194
self._origSaxStart = sax.startElementNs
9295
self._origSaxStartNoNs = sax.startElement
9396
# only override start event handler if needed
@@ -231,6 +234,16 @@ cdef inline void _pushSaxEvent(_IterparseContext context,
231234
context._c_ctxt.disableSAX = 1
232235
context._store_raised()
233236

237+
cdef void _iterparseSaxStartDocument(void* ctxt):
238+
cdef xmlparser.xmlParserCtxt* c_ctxt
239+
c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
240+
context = <_IterparseContext>c_ctxt._private
241+
context._origSaxStartDocument(ctxt)
242+
if c_ctxt.myDoc and c_ctxt.dict and not c_ctxt.myDoc.dict:
243+
# I have no idea why libxml2 disables this - we need it
244+
c_ctxt.dictNames = 1
245+
c_ctxt.myDoc.dict = c_ctxt.dict
246+
234247
cdef void _iterparseSaxStart(void* ctxt, char* localname, char* prefix,
235248
char* URI, int nb_namespaces, char** namespaces,
236249
int nb_attributes, int nb_defaulted,

src/lxml/tests/test_htmlparser.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,22 @@ def test_html_iterparse_file(self):
288288
[],
289289
[ event for (event, element) in events if event != 'end' ])
290290

291+
def test_html_iterparse_start(self):
292+
iterparse = self.etree.iterparse
293+
f = BytesIO(
294+
'<html><head><title>TITLE</title><body><p>P</p></body></html>')
295+
296+
iterator = iterparse(f, html=True, events=('start',))
297+
self.assertEquals(None, iterator.root)
298+
299+
events = list(iterator)
300+
root = iterator.root
301+
self.assert_(root is not None)
302+
self.assertEquals(
303+
[('start', root), ('start', root[0]), ('start', root[0][0]),
304+
('start', root[1]), ('start', root[1][0])],
305+
events)
306+
291307
def test_suite():
292308
suite = unittest.TestSuite()
293309
suite.addTests([unittest.makeSuite(HtmlParserTestCase)])

src/lxml/xmlparser.pxd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ cdef extern from "libxml/parser.h":
4040

4141
ctypedef void (*endDocumentSAXFunc)(void* ctx)
4242

43+
ctypedef void (*startDocumentSAXFunc)(void* ctx)
44+
4345
ctypedef void (*referenceSAXFunc)(void * ctx, char* name)
4446

4547
cdef int XML_SAX2_MAGIC
@@ -68,6 +70,7 @@ cdef extern from "libxml/tree.h":
6870
referenceSAXFunc reference
6971
commentSAXFunc comment
7072
processingInstructionSAXFunc processingInstruction
73+
startDocumentSAXFunc startDocument
7174
endDocumentSAXFunc endDocument
7275
int initialized
7376

@@ -86,6 +89,7 @@ cdef extern from "libxml/parser.h":
8689
ctypedef struct xmlParserCtxt:
8790
xmlDoc* myDoc
8891
xmlDict* dict
92+
int dictNames
8993
void* _private
9094
bint wellFormed
9195
bint recovery

0 commit comments

Comments
 (0)