Skip to content

Commit 9bbafbb

Browse files
committed
Test embedded NUL byte/character
1 parent 56d285b commit 9bbafbb

3 files changed

Lines changed: 24 additions & 7 deletions

File tree

‎Lib/test/test_codecs.py‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4067,7 +4067,8 @@ class LocaleCodecTest(unittest.TestCase):
40674067
STRINGS = ("ascii", "ulatin1:\xa7\xe9",
40684068
"u255:\xff",
40694069
"UCS:\xe9\u20ac\U0010ffff",
4070-
"surrogates:\uDC80\uDCFF")
4070+
"surrogates:\uDC80\uDCFF",
4071+
"embed\0char")
40714072
BYTES_STRINGS = (b"blatin1:\xa7\xe9", b"b255:\xff")
40724073
SURROGATES = "\uDC80\uDCFF"
40734074

@@ -4085,6 +4086,10 @@ def check_encode_strings(self, errors):
40854086
with self.subTest(text=text):
40864087
try:
40874088
expected = text.encode(self.ENCODING, errors)
4089+
if b"\0" in expected:
4090+
# Py_EncodeLocale() and _Py_EncodeLocale()
4091+
# truncate the input string at the first NUL character
4092+
expected = expected.partition(b'\0')[0]
40884093
except UnicodeEncodeError:
40894094
for error_pos in range(len(text)):
40904095
try:
@@ -4169,8 +4174,12 @@ def check_decode_strings(self, errors):
41694174
with self.subTest(encoded=encoded):
41704175
try:
41714176
expected = encoded.decode(self.ENCODING, errors)
4177+
if "\0" in expected:
4178+
# Py_DecodeLocale() and _Py_DecodeLocale() truncate
4179+
# the input string at the first NUL byte
4180+
expected = expected.partition('\0')[0]
41724181
except UnicodeDecodeError:
4173-
for error_pos in range(len(text) - 1, -1, -1):
4182+
for error_pos in range(len(encoded) - 1, -1, -1):
41744183
try:
41754184
encoded[:error_pos].decode(self.ENCODING, errors)
41764185
except UnicodeDecodeError:

‎Modules/_testinternalcapi.c‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,9 @@ encode_locale(PyObject *self, PyObject *args)
10591059
return NULL;
10601060
}
10611061

1062-
wchar_t *wstr = PyUnicode_AsWideCharString(unicode, NULL);
1062+
// Accept embedded null characters
1063+
Py_ssize_t unused_wlen;
1064+
wchar_t *wstr = PyUnicode_AsWideCharString(unicode, &unused_wlen);
10631065
if (wstr == NULL) {
10641066
return NULL;
10651067
}
@@ -1115,11 +1117,13 @@ static PyObject *
11151117
decode_locale(PyObject *self, PyObject *args)
11161118
{
11171119
char *str;
1120+
Py_ssize_t unused_len;
11181121
int current_locale = 0;
11191122
PyObject *res = NULL;
11201123
const char *errors = NULL;
1121-
1122-
if (!PyArg_ParseTuple(args, "y|is", &str, &current_locale, &errors)) {
1124+
// Accept embedded null bytes in str
1125+
if (!PyArg_ParseTuple(args, "y#|is",
1126+
&str, &unused_len, &current_locale, &errors)) {
11231127
return NULL;
11241128
}
11251129
_Py_error_handler error_handler = _Py_GetErrorHandler(errors);

‎Modules/_testlimitedcapi/codec.c‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ static PyObject *
2121
decode_locale(PyObject *Py_UNUSED(module), PyObject *arg)
2222
{
2323
const char *str;
24-
if (PyArg_Parse(arg, "y", &str) < 0) {
24+
Py_ssize_t unused_len;
25+
// Accept embedded null bytes
26+
if (PyArg_Parse(arg, "y#", &str, &unused_len) < 0) {
2527
return NULL;
2628
}
2729

@@ -61,7 +63,9 @@ encode_locale(PyObject *Py_UNUSED(module), PyObject *arg)
6163
return NULL;
6264
}
6365

64-
wchar_t *wstr = PyUnicode_AsWideCharString(unicode, NULL);
66+
// Accept embedded null characters
67+
Py_ssize_t unused_wlen;
68+
wchar_t *wstr = PyUnicode_AsWideCharString(unicode, &unused_wlen);
6569
if (wstr == NULL) {
6670
return NULL;
6771
}

0 commit comments

Comments
 (0)