@@ -1714,6 +1714,50 @@ def inner():
17141714 gc_collect () # For PyPy or other GCs.
17151715 self .assertEqual (wr (), None )
17161716
1717+ @cpython_only
1718+ def test_oserror_refleak_attributes_before_init (self ):
1719+ # gh-150988: no leak when a subclass sets OSError fields before
1720+ # super().__init__(), or when __init__ is called more than once.
1721+ import gc
1722+
1723+ class LeakingOSError (OSError ):
1724+ def __init__ (self , code , message , filename , filename2 ):
1725+ self .strerror = message
1726+ self .filename = filename
1727+ self .filename2 = filename2
1728+ super ().__init__ (code , message , filename , None , filename2 )
1729+
1730+ msg = "some error message"
1731+ filename = "some filename"
1732+ filename2 = "some filename 2"
1733+ refcount_msg = sys .getrefcount (msg )
1734+ refcount_filename = sys .getrefcount (filename )
1735+ refcount_filename2 = sys .getrefcount (filename2 )
1736+
1737+ for _ in range (5 ):
1738+ try :
1739+ raise LeakingOSError (1 , msg , filename , filename2 )
1740+ except OSError :
1741+ pass
1742+
1743+ gc_collect ()
1744+ self .assertEqual (sys .getrefcount (msg ), refcount_msg )
1745+ self .assertEqual (sys .getrefcount (filename ), refcount_filename )
1746+ self .assertEqual (sys .getrefcount (filename2 ), refcount_filename2 )
1747+
1748+ exc = LeakingOSError (1 , msg , filename , filename2 )
1749+ exc .__init__ (2 , msg , filename , filename2 )
1750+ self .assertEqual (exc .errno , 2 )
1751+ self .assertEqual (exc .strerror , msg )
1752+ self .assertEqual (exc .filename , filename )
1753+ self .assertEqual (exc .filename2 , filename2 )
1754+ del exc
1755+
1756+ gc_collect ()
1757+ self .assertEqual (sys .getrefcount (msg ), refcount_msg )
1758+ self .assertEqual (sys .getrefcount (filename ), refcount_filename )
1759+ self .assertEqual (sys .getrefcount (filename2 ), refcount_filename2 )
1760+
17171761 def test_errno_ENOTDIR (self ):
17181762 # Issue #12802: "not a directory" errors are ENOTDIR even on Windows
17191763 with self .assertRaises (OSError ) as cm :
0 commit comments