[Python-checkins] CVS: python/dist/src/Lib pickle.py,1.38,1.39

Jeremy Hylton python-dev@python.org
Fri, 15 Sep 2000 08:14:54 -0700


Update of /cvsroot/python/python/dist/src/Lib
In directory slayer.i.sourceforge.net:/tmp/cvs-serv25891/Lib

Modified Files:
	pickle.py 
Log Message:
Fix Bug #114293: 
    Strings are unpickled by calling eval on the string's repr. This
    change makes pickle work like cPickle; it checks if the pickled
    string is safe to eval and raises ValueError if it is not. 

test suite modifications:
    Verify that pickle catches a variety of insecure string pickles
    Make test_pickle and test_cpickle use exactly the same test suite
    Add test for pickling recursive object



Index: pickle.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/pickle.py,v
retrieving revision 1.38
retrieving revision 1.39
diff -C2 -r1.38 -r1.39
*** pickle.py	2000/06/29 16:15:52	1.38
--- pickle.py	2000/09/15 15:14:51	1.39
***************
*** 578,584 ****
  
      def load_string(self):
!         self.append(eval(self.readline()[:-1],
                           {'__builtins__': {}})) # Let's be careful
      dispatch[STRING] = load_string
  
      def load_binstring(self):
--- 578,624 ----
  
      def load_string(self):
!         rep = self.readline()[:-1]
!         if not self._is_string_secure(rep):
!             raise ValueError, "insecure string pickle"
!         self.append(eval(rep,
                           {'__builtins__': {}})) # Let's be careful
      dispatch[STRING] = load_string
+ 
+     def _is_string_secure(self, s):
+         """Return true if s contains a string that is safe to eval
+ 
+         The definition of secure string is based on the implementation
+         in cPickle.  s is secure as long as it only contains a quoted
+         string and optional trailing whitespace.
+         """
+         q = s[0]
+         if q not in ("'", '"'):
+             return 0
+         # find the closing quote
+         offset = 1
+         i = None
+         while 1:
+             try:
+                 i = s.index(q, offset)
+             except ValueError:
+                 # if there is an error the first time, there is no
+                 # close quote
+                 if offset == 1:
+                     return 0
+             if s[i-1] != '\\':
+                 break
+             # check to see if this one is escaped
+             nslash = 0
+             j = i - 1
+             while j >= offset and s[j] == '\\':
+                 j = j - 1
+                 nslash = nslash + 1
+             if nslash % 2 == 0:
+                 break
+             offset = i + 1
+         for c in s[i+1:]:
+             if ord(c) > 32:
+                 return 0
+         return 1
  
      def load_binstring(self):