File tree Expand file tree Collapse file tree 3 files changed +28
-3
lines changed
Expand file tree Collapse file tree 3 files changed +28
-3
lines changed Original file line number Diff line number Diff line change @@ -505,13 +505,16 @@ def _is_wrapper(f):
505505 def _is_wrapper (f ):
506506 return hasattr (f , '__wrapped__' ) and not stop (f )
507507 f = func # remember the original func for error reporting
508- memo = {id (f )} # Memoise by id to tolerate non-hashable objects
508+ # Memoise by id to tolerate non-hashable objects, but store objects to
509+ # ensure they aren't destroyed, which would allow their IDs to be reused.
510+ memo = {id (f ): f }
511+ recursion_limit = sys .getrecursionlimit ()
509512 while _is_wrapper (func ):
510513 func = func .__wrapped__
511514 id_func = id (func )
512- if id_func in memo :
515+ if ( id_func in memo ) or ( len ( memo ) >= recursion_limit ) :
513516 raise ValueError ('wrapper loop when unwrapping {!r}' .format (f ))
514- memo . add ( id_func )
517+ memo [ id_func ] = func
515518 return func
516519
517520# -------------------------------------------------- source code extraction
Original file line number Diff line number Diff line change @@ -3554,6 +3554,19 @@ def test_builtins_have_signatures(self):
35543554 self .assertIsNone (obj .__text_signature__ )
35553555
35563556
3557+ class NTimesUnwrappable :
3558+ def __init__ (self , n ):
3559+ self .n = n
3560+ self ._next = None
3561+
3562+ @property
3563+ def __wrapped__ (self ):
3564+ if self .n <= 0 :
3565+ raise Exception ("Unwrapped too many times" )
3566+ if self ._next is None :
3567+ self ._next = NTimesUnwrappable (self .n - 1 )
3568+ return self ._next
3569+
35573570class TestUnwrap (unittest .TestCase ):
35583571
35593572 def test_unwrap_one (self ):
@@ -3609,6 +3622,11 @@ class C:
36093622 __wrapped__ = func
36103623 self .assertIsNone (inspect .unwrap (C ()))
36113624
3625+ def test_recursion_limit (self ):
3626+ obj = NTimesUnwrappable (sys .getrecursionlimit () + 1 )
3627+ with self .assertRaisesRegex (ValueError , 'wrapper loop' ):
3628+ inspect .unwrap (obj )
3629+
36123630class TestMain (unittest .TestCase ):
36133631 def test_only_source (self ):
36143632 module = importlib .import_module ('unittest' )
Original file line number Diff line number Diff line change @@ -995,6 +995,10 @@ Library
995995- Issue #29581: ABCMeta.__new__ now accepts ``**kwargs``, allowing abstract base
996996 classes to use keyword parameters in __init_subclass__. Patch by Nate Soares.
997997
998+ - Issue #25532: inspect.unwrap() will now only try to unwrap an object
999+ sys.getrecursionlimit() times, to protect against objects which create a new
1000+ object on every attribute access.
1001+
9981002Windows
9991003-------
10001004
You can’t perform that action at this time.
0 commit comments