@@ -514,6 +514,70 @@ def test_partial_genericalias(self):
514514 self .assertEqual (alias .__args__ , (int ,))
515515 self .assertEqual (alias .__parameters__ , ())
516516
517+ # Issue 144475
518+ def test_repr_for_segfault (self ):
519+ g_partial = None
520+
521+ class Function :
522+ def __init__ (self , name ):
523+ self .name = name
524+
525+ def __call__ (self ):
526+ return None
527+
528+ def __repr__ (self ):
529+ return f"Function({ self .name } )"
530+
531+ class EvilObject :
532+ def __init__ (self , name , is_trigger = False ):
533+ self .name = name
534+ self .is_trigger = is_trigger
535+ self .triggered = False
536+
537+ def __repr__ (self ):
538+ if self .is_trigger and not self .triggered and g_partial is not None :
539+ self .triggered = True
540+ new_args_tuple = (None ,)
541+ new_keywords_dict = {"keyword" : None }
542+ new_tuple_state = (Function ("new_function" ), new_args_tuple , new_keywords_dict , None )
543+ g_partial .__setstate__ (new_tuple_state )
544+ gc .collect ()
545+ return f"EvilObject({ self .name } )"
546+
547+ trigger = EvilObject ("trigger" , is_trigger = True )
548+ victim = EvilObject ("victim" )
549+
550+ p = functools .partial (Function ("old_function" ), victim , victim = trigger )
551+ g_partial = p
552+ self .assertEqual (repr (g_partial ),"functools.partial(Function(old_function), EvilObject(victim), victim=EvilObject(trigger))" )
553+
554+ trigger .triggered = False
555+ g_partial = None
556+ p = functools .partial (Function ("old_function" ), trigger , victim = victim )
557+ g_partial = p
558+ self .assertEqual (repr (g_partial ),"functools.partial(Function(old_function), EvilObject(trigger), victim=EvilObject(victim))" )
559+
560+
561+ trigger .triggered = False
562+ p = functools .partial (Function ("old_function" ), trigger , victim )
563+ g_partial = p
564+
565+ trigger .triggered = False
566+ p = functools .partial (Function ("old_function" ), trigger = trigger , victim = victim )
567+ g_partial = p
568+ self .assertEqual (repr (g_partial ),"functools.partial(Function(old_function), trigger=EvilObject(trigger), victim=EvilObject(victim))" )
569+
570+ trigger .triggered = False
571+ victim1 = EvilObject ("victim" )
572+ victim2 = EvilObject ("victim" )
573+ victim3 = EvilObject ("victim" )
574+ victim4 = EvilObject ("victim" )
575+ victim5 = EvilObject ("victim" )
576+ p = functools .partial (Function ("old_function" ), trigger , victim1 , victim2 , victim3 , victim4 , victim = victim5 )
577+ g_partial = p
578+ self .assertEqual (repr (g_partial ),"functools.partial(Function(old_function), EvilObject(trigger), EvilObject(victim), EvilObject(victim), EvilObject(victim), EvilObject(victim), victim=EvilObject(victim))" )
579+
580+
517581
518582@unittest .skipUnless (c_functools , 'requires the C _functools module' )
519583class TestPartialC (TestPartial , unittest .TestCase ):
0 commit comments