@@ -353,6 +353,69 @@ _Pickle_FastCall(PyObject *func, PyObject *obj)
353
353
354
354
/*************************************************************************/
355
355
356
+ /* Retrieve and deconstruct a method for avoiding a reference cycle
357
+ (pickler -> bound method of pickler -> pickler) */
358
+ static int
359
+ init_method_ref (PyObject * self , _Py_Identifier * name ,
360
+ PyObject * * method_func , PyObject * * method_self )
361
+ {
362
+ PyObject * func , * func2 ;
363
+
364
+ /* *method_func and *method_self should be consistent. All refcount decrements
365
+ should be occurred after setting *method_self and *method_func. */
366
+ func = _PyObject_GetAttrId (self , name );
367
+ if (func == NULL ) {
368
+ * method_self = NULL ;
369
+ Py_CLEAR (* method_func );
370
+ if (!PyErr_ExceptionMatches (PyExc_AttributeError )) {
371
+ return -1 ;
372
+ }
373
+ PyErr_Clear ();
374
+ return 0 ;
375
+ }
376
+
377
+ if (PyMethod_Check (func ) && PyMethod_GET_SELF (func ) == self ) {
378
+ /* Deconstruct a bound Python method */
379
+ func2 = PyMethod_GET_FUNCTION (func );
380
+ Py_INCREF (func2 );
381
+ * method_self = self ; /* borrowed */
382
+ Py_XSETREF (* method_func , func2 );
383
+ Py_DECREF (func );
384
+ return 0 ;
385
+ }
386
+ else {
387
+ * method_self = NULL ;
388
+ Py_XSETREF (* method_func , func );
389
+ return 0 ;
390
+ }
391
+ }
392
+
393
+ /* Bind a method if it was deconstructed */
394
+ static PyObject *
395
+ reconstruct_method (PyObject * func , PyObject * self )
396
+ {
397
+ if (self ) {
398
+ return PyMethod_New (func , self );
399
+ }
400
+ else {
401
+ Py_INCREF (func );
402
+ return func ;
403
+ }
404
+ }
405
+
406
+ static PyObject *
407
+ call_method (PyObject * func , PyObject * self , PyObject * obj )
408
+ {
409
+ if (self ) {
410
+ return PyObject_CallFunctionObjArgs (func , self , obj , NULL );
411
+ }
412
+ else {
413
+ return PyObject_CallFunctionObjArgs (func , obj , NULL );
414
+ }
415
+ }
416
+
417
+ /*************************************************************************/
418
+
356
419
/* Internal data type used as the unpickling stack. */
357
420
typedef struct {
358
421
PyObject_VAR_HEAD
@@ -545,6 +608,8 @@ typedef struct PicklerObject {
545
608
objects to support self-referential objects
546
609
pickling. */
547
610
PyObject * pers_func ; /* persistent_id() method, can be NULL */
611
+ PyObject * pers_func_self ; /* borrowed reference to self if pers_func
612
+ is an unbound method, NULL otherwise */
548
613
PyObject * dispatch_table ; /* private dispatch_table, can be NULL */
549
614
550
615
PyObject * write ; /* write() method of the output stream. */
@@ -583,6 +648,8 @@ typedef struct UnpicklerObject {
583
648
Py_ssize_t memo_len ; /* Number of objects in the memo */
584
649
585
650
PyObject * pers_func ; /* persistent_load() method, can be NULL. */
651
+ PyObject * pers_func_self ; /* borrowed reference to self if pers_func
652
+ is an unbound method, NULL otherwise */
586
653
587
654
Py_buffer buffer ;
588
655
char * input_buffer ;
@@ -3401,16 +3468,15 @@ save_type(PicklerObject *self, PyObject *obj)
3401
3468
}
3402
3469
3403
3470
static int
3404
- save_pers (PicklerObject * self , PyObject * obj , PyObject * func )
3471
+ save_pers (PicklerObject * self , PyObject * obj )
3405
3472
{
3406
3473
PyObject * pid = NULL ;
3407
3474
int status = 0 ;
3408
3475
3409
3476
const char persid_op = PERSID ;
3410
3477
const char binpersid_op = BINPERSID ;
3411
3478
3412
- Py_INCREF (obj );
3413
- pid = _Pickle_FastCall (func , obj );
3479
+ pid = call_method (self -> pers_func , self -> pers_func_self , obj );
3414
3480
if (pid == NULL )
3415
3481
return -1 ;
3416
3482
@@ -3788,7 +3854,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
3788
3854
0 if it did nothing successfully;
3789
3855
1 if a persistent id was saved.
3790
3856
*/
3791
- if ((status = save_pers (self , obj , self -> pers_func )) != 0 )
3857
+ if ((status = save_pers (self , obj )) != 0 )
3792
3858
goto done ;
3793
3859
}
3794
3860
@@ -4203,13 +4269,10 @@ _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file,
4203
4269
self -> fast_nesting = 0 ;
4204
4270
self -> fast_memo = NULL ;
4205
4271
4206
- self -> pers_func = _PyObject_GetAttrId ((PyObject * )self ,
4207
- & PyId_persistent_id );
4208
- if (self -> pers_func == NULL ) {
4209
- if (!PyErr_ExceptionMatches (PyExc_AttributeError )) {
4210
- return -1 ;
4211
- }
4212
- PyErr_Clear ();
4272
+ if (init_method_ref ((PyObject * )self , & PyId_persistent_id ,
4273
+ & self -> pers_func , & self -> pers_func_self ) < 0 )
4274
+ {
4275
+ return -1 ;
4213
4276
}
4214
4277
4215
4278
self -> dispatch_table = _PyObject_GetAttrId ((PyObject * )self ,
@@ -4476,11 +4539,11 @@ Pickler_set_memo(PicklerObject *self, PyObject *obj)
4476
4539
static PyObject *
4477
4540
Pickler_get_persid (PicklerObject * self )
4478
4541
{
4479
- if (self -> pers_func == NULL )
4542
+ if (self -> pers_func == NULL ) {
4480
4543
PyErr_SetString (PyExc_AttributeError , "persistent_id" );
4481
- else
4482
- Py_INCREF ( self -> pers_func );
4483
- return self -> pers_func ;
4544
+ return NULL ;
4545
+ }
4546
+ return reconstruct_method ( self -> pers_func , self -> pers_func_self ) ;
4484
4547
}
4485
4548
4486
4549
static int
@@ -4497,6 +4560,7 @@ Pickler_set_persid(PicklerObject *self, PyObject *value)
4497
4560
return -1 ;
4498
4561
}
4499
4562
4563
+ self -> pers_func_self = NULL ;
4500
4564
Py_INCREF (value );
4501
4565
Py_XSETREF (self -> pers_func , value );
4502
4566
@@ -5446,7 +5510,7 @@ load_stack_global(UnpicklerObject *self)
5446
5510
static int
5447
5511
load_persid (UnpicklerObject * self )
5448
5512
{
5449
- PyObject * pid ;
5513
+ PyObject * pid , * obj ;
5450
5514
Py_ssize_t len ;
5451
5515
char * s ;
5452
5516
@@ -5466,13 +5530,12 @@ load_persid(UnpicklerObject *self)
5466
5530
return -1 ;
5467
5531
}
5468
5532
5469
- /* This does not leak since _Pickle_FastCall() steals the reference
5470
- to pid first. */
5471
- pid = _Pickle_FastCall (self -> pers_func , pid );
5472
- if (pid == NULL )
5533
+ obj = call_method (self -> pers_func , self -> pers_func_self , pid );
5534
+ Py_DECREF (pid );
5535
+ if (obj == NULL )
5473
5536
return -1 ;
5474
5537
5475
- PDATA_PUSH (self -> stack , pid , -1 );
5538
+ PDATA_PUSH (self -> stack , obj , -1 );
5476
5539
return 0 ;
5477
5540
}
5478
5541
else {
@@ -5487,20 +5550,19 @@ load_persid(UnpicklerObject *self)
5487
5550
static int
5488
5551
load_binpersid (UnpicklerObject * self )
5489
5552
{
5490
- PyObject * pid ;
5553
+ PyObject * pid , * obj ;
5491
5554
5492
5555
if (self -> pers_func ) {
5493
5556
PDATA_POP (self -> stack , pid );
5494
5557
if (pid == NULL )
5495
5558
return -1 ;
5496
5559
5497
- /* This does not leak since _Pickle_FastCall() steals the
5498
- reference to pid first. */
5499
- pid = _Pickle_FastCall (self -> pers_func , pid );
5500
- if (pid == NULL )
5560
+ obj = call_method (self -> pers_func , self -> pers_func_self , pid );
5561
+ Py_DECREF (pid );
5562
+ if (obj == NULL )
5501
5563
return -1 ;
5502
5564
5503
- PDATA_PUSH (self -> stack , pid , -1 );
5565
+ PDATA_PUSH (self -> stack , obj , -1 );
5504
5566
return 0 ;
5505
5567
}
5506
5568
else {
@@ -6637,13 +6699,10 @@ _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file,
6637
6699
6638
6700
self -> fix_imports = fix_imports ;
6639
6701
6640
- self -> pers_func = _PyObject_GetAttrId ((PyObject * )self ,
6641
- & PyId_persistent_load );
6642
- if (self -> pers_func == NULL ) {
6643
- if (!PyErr_ExceptionMatches (PyExc_AttributeError )) {
6644
- return -1 ;
6645
- }
6646
- PyErr_Clear ();
6702
+ if (init_method_ref ((PyObject * )self , & PyId_persistent_load ,
6703
+ & self -> pers_func , & self -> pers_func_self ) < 0 )
6704
+ {
6705
+ return -1 ;
6647
6706
}
6648
6707
6649
6708
self -> stack = (Pdata * )Pdata_New ();
@@ -6930,11 +6989,11 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
6930
6989
static PyObject *
6931
6990
Unpickler_get_persload (UnpicklerObject * self )
6932
6991
{
6933
- if (self -> pers_func == NULL )
6992
+ if (self -> pers_func == NULL ) {
6934
6993
PyErr_SetString (PyExc_AttributeError , "persistent_load" );
6935
- else
6936
- Py_INCREF ( self -> pers_func );
6937
- return self -> pers_func ;
6994
+ return NULL ;
6995
+ }
6996
+ return reconstruct_method ( self -> pers_func , self -> pers_func_self ) ;
6938
6997
}
6939
6998
6940
6999
static int
@@ -6952,6 +7011,7 @@ Unpickler_set_persload(UnpicklerObject *self, PyObject *value)
6952
7011
return -1 ;
6953
7012
}
6954
7013
7014
+ self -> pers_func_self = NULL ;
6955
7015
Py_INCREF (value );
6956
7016
Py_XSETREF (self -> pers_func , value );
6957
7017
0 commit comments