Skip to content

Commit

Permalink
bpo-31829: Make protocol 0 pickles be loadable in text mode in Python…
Browse files Browse the repository at this point in the history
… 2. (GH-11859)

Escape ``\r``, ``\0`` and ``\x1a`` (end-of-file on Windows) in Unicode strings.
(cherry picked from commit 38ab7d4)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
  • Loading branch information
miss-islington and serhiy-storchaka authored Jun 12, 2019
1 parent 534136a commit d561f84
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 5 deletions.
3 changes: 3 additions & 0 deletions Lib/pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,10 @@ def save_str(self, obj):
self.write(BINUNICODE + pack("<I", n) + encoded)
else:
obj = obj.replace("\\", "\\u005c")
obj = obj.replace("\0", "\\u0000")
obj = obj.replace("\n", "\\u000a")
obj = obj.replace("\r", "\\u000d")
obj = obj.replace("\x1a", "\\u001a") # EOF on DOS
self.write(UNICODE + obj.encode('raw-unicode-escape') +
b'\n')
self.memoize(obj)
Expand Down
19 changes: 15 additions & 4 deletions Lib/test/pickletester.py
Original file line number Diff line number Diff line change
Expand Up @@ -2709,22 +2709,20 @@ def __getattr__(self, key):
class AbstractPickleModuleTests(unittest.TestCase):

def test_dump_closed_file(self):
import os
f = open(TESTFN, "wb")
try:
f.close()
self.assertRaises(ValueError, self.dump, 123, f)
finally:
os.remove(TESTFN)
support.unlink(TESTFN)

def test_load_closed_file(self):
import os
f = open(TESTFN, "wb")
try:
f.close()
self.assertRaises(ValueError, self.dump, 123, f)
finally:
os.remove(TESTFN)
support.unlink(TESTFN)

def test_load_from_and_dump_to_file(self):
stream = io.BytesIO()
Expand All @@ -2748,6 +2746,19 @@ def test_callapi(self):
self.Pickler(f, -1)
self.Pickler(f, protocol=-1)

def test_dump_text_file(self):
f = open(TESTFN, "w")
try:
for proto in protocols:
self.assertRaises(TypeError, self.dump, 123, f, proto)
finally:
f.close()
support.unlink(TESTFN)

def test_incomplete_input(self):
s = io.BytesIO(b"X''.")
self.assertRaises((EOFError, struct.error, pickle.UnpicklingError), self.load, s)

def test_bad_init(self):
# Test issue3664 (pickle can segfault from a badly initialized Pickler).
# Override initialization without calling __init__() of the superclass.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
``\r``, ``\0`` and ``\x1a`` (end-of-file on Windows) are now escaped in
protocol 0 pickles of Unicode strings. This allows to load them without loss
from files open in text mode in Python 2.
5 changes: 4 additions & 1 deletion Modules/_pickle.c
Original file line number Diff line number Diff line change
Expand Up @@ -2337,7 +2337,10 @@ raw_unicode_escape(PyObject *obj)
*p++ = Py_hexdigits[ch & 15];
}
/* Map 16-bit characters, '\\' and '\n' to '\uxxxx' */
else if (ch >= 256 || ch == '\\' || ch == '\n') {
else if (ch >= 256 ||
ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' ||
ch == 0x1a)
{
/* -1: subtract 1 preallocated byte */
p = _PyBytesWriter_Prepare(&writer, p, 6-1);
if (p == NULL)
Expand Down

0 comments on commit d561f84

Please sign in to comment.