@@ -316,7 +316,9 @@ call_with_frame(const char *funcname, int lineno, PyObject* func, PyObject* args
316316{
317317 PyObject * res ;
318318
319+ Py_INCREF (func );
319320 res = PyObject_Call (func , args , NULL );
321+ Py_DECREF (func );
320322 if (res == NULL ) {
321323 _PyTraceback_Add (funcname , __FILE__ , lineno );
322324 XML_StopParser (self -> itself , XML_FALSE );
@@ -356,19 +358,25 @@ call_character_handler(xmlparseobject *self, const XML_Char *buffer, int len)
356358 if (!have_handler (self , CharacterData ))
357359 return -1 ;
358360
359- args = PyTuple_New (1 );
360- if (args == NULL )
361- return -1 ;
362- temp = (conv_string_len_to_unicode (buffer , len ));
361+ /* Copy the buffer before tuple allocation can trigger a GC callback. */
362+ temp = conv_string_len_to_unicode (buffer , len );
363363 if (temp == NULL ) {
364- Py_DECREF (args );
365364 flag_error (self );
366365 XML_SetCharacterDataHandler (self -> itself ,
367366 noop_character_data_handler );
368367 return -1 ;
369368 }
369+ args = PyTuple_New (1 );
370+ if (args == NULL ) {
371+ Py_DECREF (temp );
372+ return -1 ;
373+ }
370374 PyTuple_SET_ITEM (args , 0 , temp );
371375 /* temp is now a borrowed reference; consider it unused. */
376+ if (!have_handler (self , CharacterData )) {
377+ Py_DECREF (args );
378+ return 0 ;
379+ }
372380 self -> in_callback = 1 ;
373381 temp = call_with_frame ("CharacterData" , __LINE__ ,
374382 self -> handlers [CharacterData ], args , self );
@@ -388,12 +396,13 @@ call_character_handler(xmlparseobject *self, const XML_Char *buffer, int len)
388396static int
389397flush_character_buffer (xmlparseobject * self )
390398{
391- int rc ;
392399 if (self -> buffer == NULL || self -> buffer_used == 0 )
393400 return 0 ;
394- rc = call_character_handler (self , self -> buffer , self -> buffer_used );
401+ int len = self -> buffer_used ;
402+ /* The callback may change buffering or install a new handler, which
403+ also flushes. Do not expose the same pending data a second time. */
395404 self -> buffer_used = 0 ;
396- return rc ;
405+ return call_character_handler ( self , self -> buffer , len ) ;
397406}
398407
399408static void
@@ -404,27 +413,22 @@ my_CharacterDataHandler(void *userData, const XML_Char *data, int len)
404413 if (PyErr_Occurred ())
405414 return ;
406415
407- if (self -> buffer == NULL )
416+ if (self -> buffer != NULL &&
417+ len > (self -> buffer_size - self -> buffer_used )) {
418+ if (flush_character_buffer (self ) < 0 )
419+ return ;
420+ /* The callback may replace the handler or disable buffering. */
421+ if (!have_handler (self , CharacterData ))
422+ return ;
423+ }
424+ if (self -> buffer == NULL ||
425+ len > (self -> buffer_size - self -> buffer_used )) {
408426 call_character_handler (self , data , len );
427+ }
409428 else {
410- if (len > (self -> buffer_size - self -> buffer_used )) {
411- if (flush_character_buffer (self ) < 0 )
412- return ;
413- /* handler might have changed; drop the rest on the floor
414- * if there isn't a handler anymore
415- */
416- if (!have_handler (self , CharacterData ))
417- return ;
418- }
419- if (len > self -> buffer_size ) {
420- call_character_handler (self , data , len );
421- self -> buffer_used = 0 ;
422- }
423- else {
424- memcpy (self -> buffer + self -> buffer_used ,
425- data , len * sizeof (XML_Char ));
426- self -> buffer_used += len ;
427- }
429+ memcpy (self -> buffer + self -> buffer_used ,
430+ data , len * sizeof (XML_Char ));
431+ self -> buffer_used += len ;
428432 }
429433}
430434
@@ -455,7 +459,9 @@ my_StartElementHandler(void *userData,
455459 max += 2 ;
456460 }
457461 /* Build the container. */
458- if (self -> ordered_attributes )
462+ /* Intern-dictionary comparisons can change the mode mid-loop. */
463+ int ordered_attributes = self -> ordered_attributes ;
464+ if (ordered_attributes )
459465 container = PyList_New (max );
460466 else
461467 container = PyDict_New ();
@@ -478,7 +484,7 @@ my_StartElementHandler(void *userData,
478484 Py_DECREF (n );
479485 return ;
480486 }
481- if (self -> ordered_attributes ) {
487+ if (ordered_attributes ) {
482488 PyList_SET_ITEM (container , i , n );
483489 PyList_SET_ITEM (container , i + 1 , v );
484490 }
@@ -504,6 +510,10 @@ my_StartElementHandler(void *userData,
504510 return ;
505511 }
506512 /* Container is now a borrowed reference; ignore it. */
513+ if (!have_handler (self , StartElement )) {
514+ Py_DECREF (args );
515+ return ;
516+ }
507517 self -> in_callback = 1 ;
508518 rv = call_with_frame ("StartElement" , __LINE__ ,
509519 self -> handlers [StartElement ], args , self );
@@ -560,6 +570,10 @@ my_ ## NAME ## Handler PARAMS { \
560570 flag_error(self); \
561571 return RETURN_VARIABLE; \
562572 } \
573+ if (!have_handler(self, NAME)) { \
574+ Py_DECREF(args); \
575+ return RETURN_VARIABLE; \
576+ } \
563577 self->in_callback = 1; \
564578 PyObject *rv = call_with_frame( \
565579 #NAME, __LINE__, \
@@ -708,6 +722,9 @@ my_ElementDeclHandler(void *userData,
708722 flag_error (self );
709723 goto finally ;
710724 }
725+ if (!have_handler (self , ElementDecl )) {
726+ goto finally ;
727+ }
711728 self -> in_callback = 1 ;
712729 rv = call_with_frame ("ElementDecl" , __LINE__ ,
713730 self -> handlers [ElementDecl ], args , self );
0 commit comments