Commit 35b9c79f authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #23215: Multibyte codecs with custom error handlers that ignores errors

consumed too much memory and raised SystemError or MemoryError.
Original patch by Aleksi Torhamo.
parent b349bbfa
...@@ -43,6 +43,13 @@ class Test_MultibyteCodec(unittest.TestCase): ...@@ -43,6 +43,13 @@ class Test_MultibyteCodec(unittest.TestCase):
self.assertRaises(IndexError, dec, self.assertRaises(IndexError, dec,
'apple\x92ham\x93spam', 'test.cjktest') 'apple\x92ham\x93spam', 'test.cjktest')
def test_errorcallback_custom_ignore(self):
# Issue #23215: MemoryError with custom error handlers and multibyte codecs
data = 100 * unichr(0xdc00)
codecs.register_error("test.ignore", codecs.ignore_errors)
for enc in ALL_CJKENCODINGS:
self.assertEqual(data.encode(enc, "test.ignore"), b'')
def test_codingspec(self): def test_codingspec(self):
for enc in ALL_CJKENCODINGS: for enc in ALL_CJKENCODINGS:
code = '# coding: {}\n'.format(enc) code = '# coding: {}\n'.format(enc)
......
...@@ -18,6 +18,10 @@ Core and Builtins ...@@ -18,6 +18,10 @@ Core and Builtins
Library Library
------- -------
- Issue #23215: Multibyte codecs with custom error handlers that ignores errors
consumed too much memory and raised SystemError or MemoryError.
Original patch by Aleksi Torhamo.
- Issue #5700: io.FileIO() called flush() after closing the file. - Issue #5700: io.FileIO() called flush() after closing the file.
flush() was not called in close() if closefd=False. flush() was not called in close() if closefd=False.
......
...@@ -170,8 +170,10 @@ expand_encodebuffer(MultibyteEncodeBuffer *buf, Py_ssize_t esize) ...@@ -170,8 +170,10 @@ expand_encodebuffer(MultibyteEncodeBuffer *buf, Py_ssize_t esize)
orgsize = PyString_GET_SIZE(buf->outobj); orgsize = PyString_GET_SIZE(buf->outobj);
incsize = (esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize); incsize = (esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize);
if (orgsize > PY_SSIZE_T_MAX - incsize) if (orgsize > PY_SSIZE_T_MAX - incsize) {
PyErr_NoMemory();
return -1; return -1;
}
if (_PyString_Resize(&buf->outobj, orgsize + incsize) == -1) if (_PyString_Resize(&buf->outobj, orgsize + incsize) == -1)
return -1; return -1;
...@@ -182,11 +184,11 @@ expand_encodebuffer(MultibyteEncodeBuffer *buf, Py_ssize_t esize) ...@@ -182,11 +184,11 @@ expand_encodebuffer(MultibyteEncodeBuffer *buf, Py_ssize_t esize)
return 0; return 0;
} }
#define REQUIRE_ENCODEBUFFER(buf, s) { \ #define REQUIRE_ENCODEBUFFER(buf, s) do { \
if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \ if ((s) < 0 || (s) > (buf)->outbuf_end - (buf)->outbuf) \
if (expand_encodebuffer(buf, s) == -1) \ if (expand_encodebuffer(buf, s) == -1) \
goto errorexit; \ goto errorexit; \
} } while(0)
static int static int
expand_decodebuffer(MultibyteDecodeBuffer *buf, Py_ssize_t esize) expand_decodebuffer(MultibyteDecodeBuffer *buf, Py_ssize_t esize)
...@@ -205,11 +207,11 @@ expand_decodebuffer(MultibyteDecodeBuffer *buf, Py_ssize_t esize) ...@@ -205,11 +207,11 @@ expand_decodebuffer(MultibyteDecodeBuffer *buf, Py_ssize_t esize)
return 0; return 0;
} }
#define REQUIRE_DECODEBUFFER(buf, s) { \ #define REQUIRE_DECODEBUFFER(buf, s) do { \
if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \ if ((s) < 0 || (s) > (buf)->outbuf_end - (buf)->outbuf) \
if (expand_decodebuffer(buf, s) == -1) \ if (expand_decodebuffer(buf, s) == -1) \
goto errorexit; \ goto errorexit; \
} } while(0)
/** /**
...@@ -327,10 +329,11 @@ multibytecodec_encerror(MultibyteCodec *codec, ...@@ -327,10 +329,11 @@ multibytecodec_encerror(MultibyteCodec *codec,
} }
retstrsize = PyString_GET_SIZE(retstr); retstrsize = PyString_GET_SIZE(retstr);
REQUIRE_ENCODEBUFFER(buf, retstrsize); if (retstrsize > 0) {
REQUIRE_ENCODEBUFFER(buf, retstrsize);
memcpy(buf->outbuf, PyString_AS_STRING(retstr), retstrsize); memcpy(buf->outbuf, PyString_AS_STRING(retstr), retstrsize);
buf->outbuf += retstrsize; buf->outbuf += retstrsize;
}
newpos = PyInt_AsSsize_t(PyTuple_GET_ITEM(retobj, 1)); newpos = PyInt_AsSsize_t(PyTuple_GET_ITEM(retobj, 1));
if (newpos < 0 && !PyErr_Occurred()) if (newpos < 0 && !PyErr_Occurred())
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment