@@ -317,7 +317,9 @@ call_with_frame(const char *funcname, int lineno, PyObject* func, PyObject* args
317317{
318318 PyObject * res ;
319319
320+ Py_INCREF (func );
320321 res = PyObject_Call (func , args , NULL );
322+ Py_DECREF (func );
321323 if (res == NULL ) {
322324 _PyTraceback_Add (funcname , __FILE__ , lineno );
323325 XML_StopParser (self -> itself , XML_FALSE );
@@ -357,19 +359,25 @@ call_character_handler(xmlparseobject *self, const XML_Char *buffer, int len)
357359 if (!have_handler (self , CharacterData ))
358360 return -1 ;
359361
360- args = PyTuple_New (1 );
361- if (args == NULL )
362- return -1 ;
363- temp = (conv_string_len_to_unicode (buffer , len ));
362+ /* Copy the buffer before tuple allocation can trigger a GC callback. */
363+ temp = conv_string_len_to_unicode (buffer , len );
364364 if (temp == NULL ) {
365- Py_DECREF (args );
366365 flag_error (self );
367366 XML_SetCharacterDataHandler (self -> itself ,
368367 noop_character_data_handler );
369368 return -1 ;
370369 }
370+ args = PyTuple_New (1 );
371+ if (args == NULL ) {
372+ Py_DECREF (temp );
373+ return -1 ;
374+ }
371375 PyTuple_SET_ITEM (args , 0 , temp );
372376 /* temp is now a borrowed reference; consider it unused. */
377+ if (!have_handler (self , CharacterData )) {
378+ Py_DECREF (args );
379+ return 0 ;
380+ }
373381 self -> in_callback = 1 ;
374382 temp = call_with_frame ("CharacterData" , __LINE__ ,
375383 self -> handlers [CharacterData ], args , self );
@@ -389,12 +397,13 @@ call_character_handler(xmlparseobject *self, const XML_Char *buffer, int len)
389397static int
390398flush_character_buffer (xmlparseobject * self )
391399{
392- int rc ;
393400 if (self -> buffer == NULL || self -> buffer_used == 0 )
394401 return 0 ;
395- rc = call_character_handler (self , self -> buffer , self -> buffer_used );
402+ int len = self -> buffer_used ;
403+ /* The callback may change buffering or install a new handler, which
404+ also flushes. Do not expose the same pending data a second time. */
396405 self -> buffer_used = 0 ;
397- return rc ;
406+ return call_character_handler ( self , self -> buffer , len ) ;
398407}
399408
400409static void
@@ -405,27 +414,22 @@ my_CharacterDataHandler(void *userData, const XML_Char *data, int len)
405414 if (PyErr_Occurred ())
406415 return ;
407416
408- if (self -> buffer == NULL )
417+ if (self -> buffer != NULL &&
418+ len > (self -> buffer_size - self -> buffer_used )) {
419+ if (flush_character_buffer (self ) < 0 )
420+ return ;
421+ /* The callback may replace the handler or disable buffering. */
422+ if (!have_handler (self , CharacterData ))
423+ return ;
424+ }
425+ if (self -> buffer == NULL ||
426+ len > (self -> buffer_size - self -> buffer_used )) {
409427 call_character_handler (self , data , len );
428+ }
410429 else {
411- if (len > (self -> buffer_size - self -> buffer_used )) {
412- if (flush_character_buffer (self ) < 0 )
413- return ;
414- /* handler might have changed; drop the rest on the floor
415- * if there isn't a handler anymore
416- */
417- if (!have_handler (self , CharacterData ))
418- return ;
419- }
420- if (len > self -> buffer_size ) {
421- call_character_handler (self , data , len );
422- self -> buffer_used = 0 ;
423- }
424- else {
425- memcpy (self -> buffer + self -> buffer_used ,
426- data , len * sizeof (XML_Char ));
427- self -> buffer_used += len ;
428- }
430+ memcpy (self -> buffer + self -> buffer_used ,
431+ data , len * sizeof (XML_Char ));
432+ self -> buffer_used += len ;
429433 }
430434}
431435
@@ -456,7 +460,9 @@ my_StartElementHandler(void *userData,
456460 max += 2 ;
457461 }
458462 /* Build the container. */
459- if (self -> ordered_attributes )
463+ /* Intern-dictionary comparisons can change the mode mid-loop. */
464+ int ordered_attributes = self -> ordered_attributes ;
465+ if (ordered_attributes )
460466 container = PyList_New (max );
461467 else
462468 container = PyDict_New ();
@@ -479,7 +485,7 @@ my_StartElementHandler(void *userData,
479485 Py_DECREF (n );
480486 return ;
481487 }
482- if (self -> ordered_attributes ) {
488+ if (ordered_attributes ) {
483489 PyList_SET_ITEM (container , i , n );
484490 PyList_SET_ITEM (container , i + 1 , v );
485491 }
@@ -505,6 +511,10 @@ my_StartElementHandler(void *userData,
505511 return ;
506512 }
507513 /* Container is now a borrowed reference; ignore it. */
514+ if (!have_handler (self , StartElement )) {
515+ Py_DECREF (args );
516+ return ;
517+ }
508518 self -> in_callback = 1 ;
509519 rv = call_with_frame ("StartElement" , __LINE__ ,
510520 self -> handlers [StartElement ], args , self );
@@ -561,6 +571,10 @@ my_ ## NAME ## Handler PARAMS { \
561571 flag_error(self); \
562572 return RETURN_VARIABLE; \
563573 } \
574+ if (!have_handler(self, NAME)) { \
575+ Py_DECREF(args); \
576+ return RETURN_VARIABLE; \
577+ } \
564578 self->in_callback = 1; \
565579 PyObject *rv = call_with_frame( \
566580 #NAME, __LINE__, \
@@ -709,6 +723,9 @@ my_ElementDeclHandler(void *userData,
709723 flag_error (self );
710724 goto finally ;
711725 }
726+ if (!have_handler (self , ElementDecl )) {
727+ goto finally ;
728+ }
712729 self -> in_callback = 1 ;
713730 rv = call_with_frame ("ElementDecl" , __LINE__ ,
714731 self -> handlers [ElementDecl ], args , self );
0 commit comments