Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e7ab978

Browse files
authored
[3.12] gh-127208: Reject null character in _imp.create_dynamic() (#127400) (#127419)
gh-127208: Reject null character in _imp.create_dynamic() (#127400) _imp.create_dynamic() now rejects embedded null characters in the path and in the module name. Backport also the _PyUnicode_AsUTF8NoNUL() function. (cherry picked from commit b14fdad)
1 parent fc0564b commit e7ab978

File tree

4 files changed

+33
-3
lines changed

4 files changed

+33
-3
lines changed

Include/internal/pycore_unicodeobject.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ struct _Py_unicode_state {
7676

7777
extern void _PyUnicode_ClearInterned(PyInterpreterState *interp);
7878

79+
// Like PyUnicode_AsUTF8(), but check for embedded null characters.
80+
extern const char* _PyUnicode_AsUTF8NoNUL(PyObject *);
81+
7982

8083
#ifdef __cplusplus
8184
}

Lib/test/test_import/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,19 @@ def test_issue105979(self):
787787
self.assertIn("Frozen object named 'x' is invalid",
788788
str(cm.exception))
789789

790+
def test_create_dynamic_null(self):
791+
with self.assertRaisesRegex(ValueError, 'embedded null character'):
792+
class Spec:
793+
name = "a\x00b"
794+
origin = "abc"
795+
_imp.create_dynamic(Spec())
796+
797+
with self.assertRaisesRegex(ValueError, 'embedded null character'):
798+
class Spec2:
799+
name = "abc"
800+
origin = "a\x00b"
801+
_imp.create_dynamic(Spec2())
802+
790803

791804
@skip_if_dont_write_bytecode
792805
class FilePermissionTests(unittest.TestCase):

Objects/unicodeobject.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3991,6 +3991,18 @@ PyUnicode_AsUTF8(PyObject *unicode)
39913991
return PyUnicode_AsUTF8AndSize(unicode, NULL);
39923992
}
39933993

3994+
const char *
3995+
_PyUnicode_AsUTF8NoNUL(PyObject *unicode)
3996+
{
3997+
Py_ssize_t size;
3998+
const char *s = PyUnicode_AsUTF8AndSize(unicode, &size);
3999+
if (s && strlen(s) != (size_t)size) {
4000+
PyErr_SetString(PyExc_ValueError, "embedded null character");
4001+
return NULL;
4002+
}
4003+
return s;
4004+
}
4005+
39944006
/*
39954007
PyUnicode_GetSize() has been deprecated since Python 3.3
39964008
because it returned length of Py_UNICODE.

Python/import.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -917,12 +917,14 @@ extensions_lock_release(void)
917917
static void *
918918
hashtable_key_from_2_strings(PyObject *str1, PyObject *str2, const char sep)
919919
{
920-
Py_ssize_t str1_len, str2_len;
921-
const char *str1_data = PyUnicode_AsUTF8AndSize(str1, &str1_len);
922-
const char *str2_data = PyUnicode_AsUTF8AndSize(str2, &str2_len);
920+
const char *str1_data = _PyUnicode_AsUTF8NoNUL(str1);
921+
const char *str2_data = _PyUnicode_AsUTF8NoNUL(str2);
923922
if (str1_data == NULL || str2_data == NULL) {
924923
return NULL;
925924
}
925+
Py_ssize_t str1_len = strlen(str1_data);
926+
Py_ssize_t str2_len = strlen(str2_data);
927+
926928
/* Make sure sep and the NULL byte won't cause an overflow. */
927929
assert(SIZE_MAX - str1_len - str2_len > 2);
928930
size_t size = str1_len + 1 + str2_len + 1;

0 commit comments

Comments
 (0)