@@ -3514,6 +3514,84 @@ def __init__(self): pass
35143514 self .assertRaises (pickle .PicklingError , BadPickler ().dump , 0 )
35153515 self .assertRaises (pickle .UnpicklingError , BadUnpickler ().load )
35163516
3517+ def test_unpickler_bad_file (self ):
3518+ # bpo-38384: Crash in _pickle if the read attribute raises an error.
3519+ def raises_oserror (self , * args , ** kwargs ):
3520+ raise OSError
3521+ @property
3522+ def bad_property (self ):
3523+ 1 / 0
3524+
3525+ # File without read and readline
3526+ class F :
3527+ pass
3528+ self .assertRaises ((AttributeError , TypeError ), self .Unpickler , F ())
3529+
3530+ # File without read
3531+ class F :
3532+ readline = raises_oserror
3533+ self .assertRaises ((AttributeError , TypeError ), self .Unpickler , F ())
3534+
3535+ # File without readline
3536+ class F :
3537+ read = raises_oserror
3538+ self .assertRaises ((AttributeError , TypeError ), self .Unpickler , F ())
3539+
3540+ # File with bad read
3541+ class F :
3542+ read = bad_property
3543+ readline = raises_oserror
3544+ self .assertRaises (ZeroDivisionError , self .Unpickler , F ())
3545+
3546+ # File with bad readline
3547+ class F :
3548+ readline = bad_property
3549+ read = raises_oserror
3550+ self .assertRaises (ZeroDivisionError , self .Unpickler , F ())
3551+
3552+ # File with bad readline, no read
3553+ class F :
3554+ readline = bad_property
3555+ self .assertRaises (ZeroDivisionError , self .Unpickler , F ())
3556+
3557+ # File with bad read, no readline
3558+ class F :
3559+ read = bad_property
3560+ self .assertRaises ((AttributeError , ZeroDivisionError ), self .Unpickler , F ())
3561+
3562+ # File with bad peek
3563+ class F :
3564+ peek = bad_property
3565+ read = raises_oserror
3566+ readline = raises_oserror
3567+ try :
3568+ self .Unpickler (F ())
3569+ except ZeroDivisionError :
3570+ pass
3571+
3572+ # File with bad readinto
3573+ class F :
3574+ readinto = bad_property
3575+ read = raises_oserror
3576+ readline = raises_oserror
3577+ try :
3578+ self .Unpickler (F ())
3579+ except ZeroDivisionError :
3580+ pass
3581+
3582+ def test_pickler_bad_file (self ):
3583+ # File without write
3584+ class F :
3585+ pass
3586+ self .assertRaises (TypeError , self .Pickler , F ())
3587+
3588+ # File with bad write
3589+ class F :
3590+ @property
3591+ def write (self ):
3592+ 1 / 0
3593+ self .assertRaises (ZeroDivisionError , self .Pickler , F ())
3594+
35173595 def check_dumps_loads_oob_buffers (self , dumps , loads ):
35183596 # No need to do the full gamut of tests here, just enough to
35193597 # check that dumps() and loads() redirect their arguments
0 commit comments