@@ -318,6 +318,7 @@ typedef struct Picklerobject {
318318 int buf_size ;
319319 PyObject * dispatch_table ;
320320 int fast_container ; /* count nested container dumps */
321+ PyObject * fast_memo ;
321322} Picklerobject ;
322323
323324#define FAST_LIMIT 2000
@@ -886,6 +887,51 @@ whichmodule(PyObject *global, PyObject *global_name) {
886887}
887888
888889
890+ static int
891+ fast_save_enter (Picklerobject * self , PyObject * obj )
892+ {
893+ /* if fast_container < 0, we're doing an error exit. */
894+ if (++ self -> fast_container >= FAST_LIMIT ) {
895+ PyObject * key = NULL ;
896+ if (self -> fast_memo == NULL ) {
897+ self -> fast_memo = PyDict_New ();
898+ if (self -> fast_memo == NULL ) {
899+ self -> fast_container = -1 ;
900+ return 0 ;
901+ }
902+ }
903+ key = PyLong_FromVoidPtr (obj );
904+ if (key == NULL )
905+ return 0 ;
906+ if (PyDict_GetItem (self -> fast_memo , key )) {
907+ PyErr_Format (PyExc_ValueError ,
908+ "fast mode: can't pickle cyclic objects including object type %s at %p" ,
909+ obj -> ob_type -> tp_name , obj );
910+ self -> fast_container = -1 ;
911+ return 0 ;
912+ }
913+ if (PyDict_SetItem (self -> fast_memo , key , Py_None ) < 0 ) {
914+ self -> fast_container = -1 ;
915+ return 0 ;
916+ }
917+ }
918+ return 1 ;
919+ }
920+
921+ int
922+ fast_save_leave (Picklerobject * self , PyObject * obj )
923+ {
924+ if (self -> fast_container -- >= FAST_LIMIT ) {
925+ PyObject * key = PyLong_FromVoidPtr (obj );
926+ if (key == NULL )
927+ return 0 ;
928+ if (PyDict_DelItem (self -> fast_memo , key ) < 0 ) {
929+ return 0 ;
930+ }
931+ }
932+ return 1 ;
933+ }
934+
889935static int
890936save_none (Picklerobject * self , PyObject * args ) {
891937 static char none = NONE ;
@@ -1357,15 +1403,13 @@ save_empty_tuple(Picklerobject *self, PyObject *args) {
13571403static int
13581404save_list (Picklerobject * self , PyObject * args ) {
13591405 PyObject * element = 0 ;
1360- int s_len , len , i , using_appends , res = -1 , unfast = 0 ;
1406+ int s_len , len , i , using_appends , res = -1 ;
13611407 char s [3 ];
13621408
13631409 static char append = APPEND , appends = APPENDS ;
13641410
1365- if (self -> fast && self -> fast_container ++ > FAST_LIMIT ) {
1366- self -> fast = 0 ;
1367- unfast = 1 ;
1368- }
1411+ if (self -> fast && !fast_save_enter (self , args ))
1412+ goto finally ;
13691413
13701414 if (self -> bin ) {
13711415 s [0 ] = EMPTY_LIST ;
@@ -1417,11 +1461,8 @@ save_list(Picklerobject *self, PyObject *args) {
14171461 res = 0 ;
14181462
14191463finally :
1420- if (self -> fast || unfast ) {
1421- self -> fast_container -- ;
1422- if (unfast && self -> fast_container < FAST_LIMIT )
1423- self -> fast = 1 ;
1424- }
1464+ if (self -> fast && !fast_save_leave (self , args ))
1465+ res = -1 ;
14251466
14261467 return res ;
14271468}
@@ -1430,15 +1471,13 @@ save_list(Picklerobject *self, PyObject *args) {
14301471static int
14311472save_dict (Picklerobject * self , PyObject * args ) {
14321473 PyObject * key = 0 , * value = 0 ;
1433- int i , len , res = -1 , using_setitems , unfast = 0 ;
1474+ int i , len , res = -1 , using_setitems ;
14341475 char s [3 ];
14351476
14361477 static char setitem = SETITEM , setitems = SETITEMS ;
14371478
1438- if (self -> fast && self -> fast_container ++ > FAST_LIMIT ) {
1439- self -> fast = 0 ;
1440- unfast = 1 ;
1441- }
1479+ if (self -> fast && !fast_save_enter (self , args ))
1480+ goto finally ;
14421481
14431482 if (self -> bin ) {
14441483 s [0 ] = EMPTY_DICT ;
@@ -1491,12 +1530,8 @@ save_dict(Picklerobject *self, PyObject *args) {
14911530 res = 0 ;
14921531
14931532finally :
1494- if (self -> fast || unfast ) {
1495- self -> fast_container -- ;
1496- if (unfast && self -> fast_container < FAST_LIMIT )
1497- self -> fast = 1 ;
1498- }
1499-
1533+ if (self -> fast && !fast_save_leave (self , args ))
1534+ res = -1 ;
15001535
15011536 return res ;
15021537}
@@ -1507,14 +1542,12 @@ save_inst(Picklerobject *self, PyObject *args) {
15071542 PyObject * class = 0 , * module = 0 , * name = 0 , * state = 0 ,
15081543 * getinitargs_func = 0 , * getstate_func = 0 , * class_args = 0 ;
15091544 char * module_str , * name_str ;
1510- int module_size , name_size , res = -1 , unfast = 0 ;
1545+ int module_size , name_size , res = -1 ;
15111546
15121547 static char inst = INST , obj = OBJ , build = BUILD ;
15131548
1514- if (self -> fast && self -> fast_container ++ > FAST_LIMIT ) {
1515- self -> fast = 0 ;
1516- unfast = 1 ;
1517- }
1549+ if (self -> fast && !fast_save_enter (self , args ))
1550+ goto finally ;
15181551
15191552 if ((* self -> write_func )(self , & MARKv , 1 ) < 0 )
15201553 goto finally ;
@@ -1622,11 +1655,8 @@ save_inst(Picklerobject *self, PyObject *args) {
16221655 res = 0 ;
16231656
16241657finally :
1625- if (self -> fast || unfast ) {
1626- self -> fast_container -- ;
1627- if (unfast && self -> fast_container < FAST_LIMIT )
1628- self -> fast = 1 ;
1629- }
1658+ if (self -> fast && !fast_save_leave (self , args ))
1659+ res = -1 ;
16301660
16311661 Py_XDECREF (module );
16321662 Py_XDECREF (class );
@@ -1669,7 +1699,7 @@ save_global(Picklerobject *self, PyObject *args, PyObject *name) {
16691699 mod = PyImport_ImportModule (module_str );
16701700 if (mod == NULL ) {
16711701 /* Py_ErrClear(); ?? */
1672- cPickle_ErrFormat (PicklingError ,
1702+ cPickle_ErrFormat (PicklingError ,
16731703 "Can't pickle %s: it's not found as %s.%s" ,
16741704 "OSS" , args , module , global_name );
16751705 goto finally ;
@@ -2251,6 +2281,7 @@ newPicklerobject(PyObject *file, int bin) {
22512281 self -> bin = bin ;
22522282 self -> fast = 0 ;
22532283 self -> fast_container = 0 ;
2284+ self -> fast_memo = NULL ;
22542285 self -> buf_size = 0 ;
22552286 self -> dispatch_table = NULL ;
22562287
@@ -2339,6 +2370,7 @@ static void
23392370Pickler_dealloc (Picklerobject * self ) {
23402371 Py_XDECREF (self -> write );
23412372 Py_XDECREF (self -> memo );
2373+ Py_XDECREF (self -> fast_memo );
23422374 Py_XDECREF (self -> arg );
23432375 Py_XDECREF (self -> file );
23442376 Py_XDECREF (self -> pers_func );
0 commit comments