@@ -360,6 +360,69 @@ _Pickle_FastCall(PyObject *func, PyObject *obj)
360
360
361
361
/*************************************************************************/
362
362
363
+ /* Retrieve and deconstruct a method for avoiding a reference cycle
364
+ (pickler -> bound method of pickler -> pickler) */
365
+ static int
366
+ init_method_ref (PyObject * self , _Py_Identifier * name ,
367
+ PyObject * * method_func , PyObject * * method_self )
368
+ {
369
+ PyObject * func , * func2 ;
370
+
371
+ /* *method_func and *method_self should be consistent. All refcount decrements
372
+ should be occurred after setting *method_self and *method_func. */
373
+ func = _PyObject_GetAttrId (self , name );
374
+ if (func == NULL ) {
375
+ * method_self = NULL ;
376
+ Py_CLEAR (* method_func );
377
+ if (!PyErr_ExceptionMatches (PyExc_AttributeError )) {
378
+ return -1 ;
379
+ }
380
+ PyErr_Clear ();
381
+ return 0 ;
382
+ }
383
+
384
+ if (PyMethod_Check (func ) && PyMethod_GET_SELF (func ) == self ) {
385
+ /* Deconstruct a bound Python method */
386
+ func2 = PyMethod_GET_FUNCTION (func );
387
+ Py_INCREF (func2 );
388
+ * method_self = self ; /* borrowed */
389
+ Py_XSETREF (* method_func , func2 );
390
+ Py_DECREF (func );
391
+ return 0 ;
392
+ }
393
+ else {
394
+ * method_self = NULL ;
395
+ Py_XSETREF (* method_func , func );
396
+ return 0 ;
397
+ }
398
+ }
399
+
400
+ /* Bind a method if it was deconstructed */
401
+ static PyObject *
402
+ reconstruct_method (PyObject * func , PyObject * self )
403
+ {
404
+ if (self ) {
405
+ return PyMethod_New (func , self );
406
+ }
407
+ else {
408
+ Py_INCREF (func );
409
+ return func ;
410
+ }
411
+ }
412
+
413
+ static PyObject *
414
+ call_method (PyObject * func , PyObject * self , PyObject * obj )
415
+ {
416
+ if (self ) {
417
+ return PyObject_CallFunctionObjArgs (func , self , obj , NULL );
418
+ }
419
+ else {
420
+ return PyObject_CallFunctionObjArgs (func , obj , NULL );
421
+ }
422
+ }
423
+
424
+ /*************************************************************************/
425
+
363
426
/* Internal data type used as the unpickling stack. */
364
427
typedef struct {
365
428
PyObject_VAR_HEAD
@@ -552,6 +615,8 @@ typedef struct PicklerObject {
552
615
objects to support self-referential objects
553
616
pickling. */
554
617
PyObject * pers_func ; /* persistent_id() method, can be NULL */
618
+ PyObject * pers_func_self ; /* borrowed reference to self if pers_func
619
+ is an unbound method, NULL otherwise */
555
620
PyObject * dispatch_table ; /* private dispatch_table, can be NULL */
556
621
557
622
PyObject * write ; /* write() method of the output stream. */
@@ -590,6 +655,8 @@ typedef struct UnpicklerObject {
590
655
Py_ssize_t memo_len ; /* Number of objects in the memo */
591
656
592
657
PyObject * pers_func ; /* persistent_load() method, can be NULL. */
658
+ PyObject * pers_func_self ; /* borrowed reference to self if pers_func
659
+ is an unbound method, NULL otherwise */
593
660
594
661
Py_buffer buffer ;
595
662
char * input_buffer ;
@@ -3444,16 +3511,15 @@ save_type(PicklerObject *self, PyObject *obj)
3444
3511
}
3445
3512
3446
3513
static int
3447
- save_pers (PicklerObject * self , PyObject * obj , PyObject * func )
3514
+ save_pers (PicklerObject * self , PyObject * obj )
3448
3515
{
3449
3516
PyObject * pid = NULL ;
3450
3517
int status = 0 ;
3451
3518
3452
3519
const char persid_op = PERSID ;
3453
3520
const char binpersid_op = BINPERSID ;
3454
3521
3455
- Py_INCREF (obj );
3456
- pid = _Pickle_FastCall (func , obj );
3522
+ pid = call_method (self -> pers_func , self -> pers_func_self , obj );
3457
3523
if (pid == NULL )
3458
3524
return -1 ;
3459
3525
@@ -3831,7 +3897,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
3831
3897
0 if it did nothing successfully;
3832
3898
1 if a persistent id was saved.
3833
3899
*/
3834
- if ((status = save_pers (self , obj , self -> pers_func )) != 0 )
3900
+ if ((status = save_pers (self , obj )) != 0 )
3835
3901
goto done ;
3836
3902
}
3837
3903
@@ -4246,13 +4312,10 @@ _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file,
4246
4312
self -> fast_nesting = 0 ;
4247
4313
self -> fast_memo = NULL ;
4248
4314
4249
- self -> pers_func = _PyObject_GetAttrId ((PyObject * )self ,
4250
- & PyId_persistent_id );
4251
- if (self -> pers_func == NULL ) {
4252
- if (!PyErr_ExceptionMatches (PyExc_AttributeError )) {
4253
- return -1 ;
4254
- }
4255
- PyErr_Clear ();
4315
+ if (init_method_ref ((PyObject * )self , & PyId_persistent_id ,
4316
+ & self -> pers_func , & self -> pers_func_self ) < 0 )
4317
+ {
4318
+ return -1 ;
4256
4319
}
4257
4320
4258
4321
self -> dispatch_table = _PyObject_GetAttrId ((PyObject * )self ,
@@ -4519,11 +4582,11 @@ Pickler_set_memo(PicklerObject *self, PyObject *obj)
4519
4582
static PyObject *
4520
4583
Pickler_get_persid (PicklerObject * self )
4521
4584
{
4522
- if (self -> pers_func == NULL )
4585
+ if (self -> pers_func == NULL ) {
4523
4586
PyErr_SetString (PyExc_AttributeError , "persistent_id" );
4524
- else
4525
- Py_INCREF ( self -> pers_func );
4526
- return self -> pers_func ;
4587
+ return NULL ;
4588
+ }
4589
+ return reconstruct_method ( self -> pers_func , self -> pers_func_self ) ;
4527
4590
}
4528
4591
4529
4592
static int
@@ -4540,6 +4603,7 @@ Pickler_set_persid(PicklerObject *self, PyObject *value)
4540
4603
return -1 ;
4541
4604
}
4542
4605
4606
+ self -> pers_func_self = NULL ;
4543
4607
Py_INCREF (value );
4544
4608
Py_XSETREF (self -> pers_func , value );
4545
4609
@@ -5489,7 +5553,7 @@ load_stack_global(UnpicklerObject *self)
5489
5553
static int
5490
5554
load_persid (UnpicklerObject * self )
5491
5555
{
5492
- PyObject * pid ;
5556
+ PyObject * pid , * obj ;
5493
5557
Py_ssize_t len ;
5494
5558
char * s ;
5495
5559
@@ -5509,13 +5573,12 @@ load_persid(UnpicklerObject *self)
5509
5573
return -1 ;
5510
5574
}
5511
5575
5512
- /* This does not leak since _Pickle_FastCall() steals the reference
5513
- to pid first. */
5514
- pid = _Pickle_FastCall (self -> pers_func , pid );
5515
- if (pid == NULL )
5576
+ obj = call_method (self -> pers_func , self -> pers_func_self , pid );
5577
+ Py_DECREF (pid );
5578
+ if (obj == NULL )
5516
5579
return -1 ;
5517
5580
5518
- PDATA_PUSH (self -> stack , pid , -1 );
5581
+ PDATA_PUSH (self -> stack , obj , -1 );
5519
5582
return 0 ;
5520
5583
}
5521
5584
else {
@@ -5530,20 +5593,19 @@ load_persid(UnpicklerObject *self)
5530
5593
static int
5531
5594
load_binpersid (UnpicklerObject * self )
5532
5595
{
5533
- PyObject * pid ;
5596
+ PyObject * pid , * obj ;
5534
5597
5535
5598
if (self -> pers_func ) {
5536
5599
PDATA_POP (self -> stack , pid );
5537
5600
if (pid == NULL )
5538
5601
return -1 ;
5539
5602
5540
- /* This does not leak since _Pickle_FastCall() steals the
5541
- reference to pid first. */
5542
- pid = _Pickle_FastCall (self -> pers_func , pid );
5543
- if (pid == NULL )
5603
+ obj = call_method (self -> pers_func , self -> pers_func_self , pid );
5604
+ Py_DECREF (pid );
5605
+ if (obj == NULL )
5544
5606
return -1 ;
5545
5607
5546
- PDATA_PUSH (self -> stack , pid , -1 );
5608
+ PDATA_PUSH (self -> stack , obj , -1 );
5547
5609
return 0 ;
5548
5610
}
5549
5611
else {
@@ -6690,13 +6752,10 @@ _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file,
6690
6752
6691
6753
self -> fix_imports = fix_imports ;
6692
6754
6693
- self -> pers_func = _PyObject_GetAttrId ((PyObject * )self ,
6694
- & PyId_persistent_load );
6695
- if (self -> pers_func == NULL ) {
6696
- if (!PyErr_ExceptionMatches (PyExc_AttributeError )) {
6697
- return -1 ;
6698
- }
6699
- PyErr_Clear ();
6755
+ if (init_method_ref ((PyObject * )self , & PyId_persistent_load ,
6756
+ & self -> pers_func , & self -> pers_func_self ) < 0 )
6757
+ {
6758
+ return -1 ;
6700
6759
}
6701
6760
6702
6761
self -> stack = (Pdata * )Pdata_New ();
@@ -6983,11 +7042,11 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
6983
7042
static PyObject *
6984
7043
Unpickler_get_persload (UnpicklerObject * self )
6985
7044
{
6986
- if (self -> pers_func == NULL )
7045
+ if (self -> pers_func == NULL ) {
6987
7046
PyErr_SetString (PyExc_AttributeError , "persistent_load" );
6988
- else
6989
- Py_INCREF ( self -> pers_func );
6990
- return self -> pers_func ;
7047
+ return NULL ;
7048
+ }
7049
+ return reconstruct_method ( self -> pers_func , self -> pers_func_self ) ;
6991
7050
}
6992
7051
6993
7052
static int
@@ -7005,6 +7064,7 @@ Unpickler_set_persload(UnpicklerObject *self, PyObject *value)
7005
7064
return -1 ;
7006
7065
}
7007
7066
7067
+ self -> pers_func_self = NULL ;
7008
7068
Py_INCREF (value );
7009
7069
Py_XSETREF (self -> pers_func , value );
7010
7070
0 commit comments