[Patches] Fix for memory leak in test_cpickle

Charles G Waldman cgw@fnal.gov
Fri, 14 Apr 2000 16:00:08 -0500 (CDT)


Problem description:
	
	Run the following script:
	
import test.test_cpickle
for x in xrange(1000000):
    reload(test.test_cpickle)

Watch Python's memory use go up up and away!


In the course of debugging this I also saw that cPickle is
inconsistent with pickle - if you attempt a pickle.load or pickle.dump
on a closed file, you get a ValueError, whereas the corresponding
cPickle operations give an IOError.  Since cPickle is advertised as
being compatible with pickle, I changed these exceptions to match.

Index: Modules/cPickle.c
===================================================================
RCS file: /projects/cvsroot/python/dist/src/Modules/cPickle.c,v
retrieving revision 2.39
diff -c -r2.39 cPickle.c
*** cPickle.c	2000/03/10 23:11:40	2.39
--- cPickle.c	2000/04/14 20:55:20
***************
*** 2151,2169 ****
        Py_INCREF(file);
      else
        file=Pdata_New();
! 
!     self->file = file;
  
!     UNLESS (self->memo = PyDict_New()) {
!        Py_XDECREF((PyObject *)self);
!        return NULL;
!     }
  
      if (PyFile_Check(file)) {
          self->fp = PyFile_AsFile(file);
  	if (self->fp == NULL) {
! 	    PyErr_SetString(PyExc_IOError, "output file closed");
! 	    return NULL;
  	}
          self->write_func = write_file;
      }
--- 2151,2168 ----
        Py_INCREF(file);
      else
        file=Pdata_New();
!     
!     UNLESS (self->file = file) 
!       goto err;
  
!     UNLESS (self->memo = PyDict_New()) 
!        goto err;
  
      if (PyFile_Check(file)) {
          self->fp = PyFile_AsFile(file);
  	if (self->fp == NULL) {
! 	    PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
! 	    goto err;
  	}
          self->write_func = write_file;
      }
***************
*** 4054,4063 ****
      self->safe_constructors = NULL;
      self->find_class = NULL;
  
!     UNLESS (self->memo = PyDict_New()) {
!        Py_XDECREF((PyObject *)self);
!        return NULL;
!     }
  
      Py_INCREF(f);
      self->file = f;
--- 4053,4060 ----
      self->safe_constructors = NULL;
      self->find_class = NULL;
  
!     UNLESS (self->memo = PyDict_New()) 
!        goto err;
  
      Py_INCREF(f);
      self->file = f;
***************
*** 4066,4073 ****
      if (PyFile_Check(f)) {
          self->fp = PyFile_AsFile(f);
  	if (self->fp == NULL) {
! 	    PyErr_SetString(PyExc_IOError, "input file closed");
! 	    return NULL;
  	}
          self->read_func = read_file;
          self->readline_func = readline_file;
--- 4063,4070 ----
      if (PyFile_Check(f)) {
          self->fp = PyFile_AsFile(f);
  	if (self->fp == NULL) {
! 	    PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
! 	    goto err;
  	}
          self->read_func = read_file;
          self->readline_func = readline_file;
Index: Lib/test/test_cpickle.py
===================================================================
RCS file: /projects/cvsroot/python/dist/src/Lib/test/test_cpickle.py,v
retrieving revision 1.4
diff -c -r1.4 test_cpickle.py
*** test_cpickle.py	1999/07/13 15:23:42	1.4
--- test_cpickle.py	2000/04/14 20:55:30
***************
*** 79,96 ****
      f.close()
      try:
          cPickle.dump(123, f)
!     except IOError:
          pass
      else:
!         print "dump to closed file should raise IOError"
      f = open(fn, "r")
      f.close()
      try:
          cPickle.load(f)
!     except IOError:
          pass
      else:
!         print "load from closed file should raise IOError"
      os.remove(fn)
  
      # Test specific bad cases
--- 79,96 ----
      f.close()
      try:
          cPickle.dump(123, f)
!     except ValueError:
          pass
      else:
!         print "dump to closed file should raise ValueError"
      f = open(fn, "r")
      f.close()
      try:
          cPickle.load(f)
!     except ValueError:
          pass
      else:
!         print "load from closed file should raise ValueError"
      os.remove(fn)
  
      # Test specific bad cases




Disclaimer:

                   I confirm that, to the best of my knowledge and belief, this
                   contribution is free of any claims of third parties under
                   copyright, patent or other rights or interests ("claims").  To
                   the extent that I have any such claims, I hereby grant to CNRI a
                   nonexclusive, irrevocable, royalty-free, worldwide license to
                   reproduce, distribute, perform and/or display publicly, prepare
                   derivative versions, and otherwise use this contribution as part
                   of the Python software and its related documentation, or any
                   derivative versions thereof, at no cost to CNRI or its licensed
                   users, and to authorize others to do so.

                   I acknowledge that CNRI may, at its sole discretion, decide
                   whether or not to incorporate this contribution in the Python
                   software and its related documentation.  I further grant CNRI
                   permission to use my name and other identifying information
                   provided to CNRI by me for use in connection with the Python
                   software and its related documentation.