Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-99240: Fix double-free bug in Argument Clinic str_converter generated code#99241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
13 commits
Select commitHold shift + click to select a range
06b9d4a
Fix double-free bug in Argument Clinic str_converter generated code
colorfulapplNov 8, 2022
67c3078
Add News
colorfulapplNov 8, 2022
cf16400
Use walrus operator
colorfulapplNov 9, 2022
adce0ab
Merge branch 'main' into fix_ac_str_converter_cleanup
colorfulapplNov 24, 2022
3ae2aea
Rename "post_operations" to "post_parsing"
colorfulapplNov 24, 2022
c3595e1
Add Argument Clinic functional test cases
colorfulapplNov 24, 2022
946ad3f
Simplify news
colorfulapplNov 24, 2022
7767139
Delete unnecessary function doc
colorfulapplNov 24, 2022
9d08af5
Simplify function doc
colorfulapplNov 24, 2022
aa218c4
Do not generate redundant NULL check
colorfulapplNov 24, 2022
485c7aa
Polish comment
colorfulapplNov 24, 2022
18ae693
Merge branch 'main' into fix_ac_str_converter_cleanup
colorfulapplNov 24, 2022
aea779f
Rerun make clinic
colorfulapplNov 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 11 additions & 22 deletionsLib/test/clinic.test
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1740,37 +1740,26 @@ test_str_converter_encoding(PyObject *module, PyObject *const *args, Py_ssize_t
goto exit;
}
return_value = test_str_converter_encoding_impl(module, a, b, c, d, d_length, e, e_length);
/* Post parse cleanup for a */
PyMem_FREE(a);
/* Post parse cleanup for b */
PyMem_FREE(b);
/* Post parse cleanup for c */
PyMem_FREE(c);
/* Post parse cleanup for d */
PyMem_FREE(d);
/* Post parse cleanup for e */
PyMem_FREE(e);

exit:
/* Cleanup for a */
if (a) {
PyMem_FREE(a);
}
/* Cleanup for b */
if (b) {
PyMem_FREE(b);
}
/* Cleanup for c */
if (c) {
PyMem_FREE(c);
}
/* Cleanup for d */
if (d) {
PyMem_FREE(d);
}
/* Cleanup for e */
if (e) {
PyMem_FREE(e);
}

return return_value;
}

static PyObject *
test_str_converter_encoding_impl(PyObject *module, char *a, char *b, char *c,
char *d, Py_ssize_t d_length, char *e,
Py_ssize_t e_length)
/*[clinic end generated code: output=8acb886a3843f3bc input=eb4c38e1f898f402]*/
/*[clinic end generated code: output=999c1deecfa15b0a input=eb4c38e1f898f402]*/


/*[clinic input]
Expand Down
15 changes: 15 additions & 0 deletionsLib/test/test_clinic.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1045,6 +1045,17 @@ def test_str_converter(self):
self.assertEqual(ac_tester.str_converter('a', b'b', b'c'), ('a', 'b', 'c'))
self.assertEqual(ac_tester.str_converter('a', b'b', 'c\0c'), ('a', 'b', 'c\0c'))

def test_str_converter_encoding(self):
with self.assertRaises(TypeError):
ac_tester.str_converter_encoding(1)
self.assertEqual(ac_tester.str_converter_encoding('a', 'b', 'c'), ('a', 'b', 'c'))
with self.assertRaises(TypeError):
ac_tester.str_converter_encoding('a', b'b\0b', 'c')
self.assertEqual(ac_tester.str_converter_encoding('a', b'b', bytearray([ord('c')])), ('a', 'b', 'c'))
self.assertEqual(ac_tester.str_converter_encoding('a', b'b', bytearray([ord('c'), 0, ord('c')])),
('a', 'b', 'c\x00c'))
self.assertEqual(ac_tester.str_converter_encoding('a', b'b', b'c\x00c'), ('a', 'b', 'c\x00c'))

def test_py_buffer_converter(self):
with self.assertRaises(TypeError):
ac_tester.py_buffer_converter('a', 'b')
Expand DownExpand Up@@ -1225,6 +1236,10 @@ def test_gh_99233_refcount(self):
arg_refcount_after = sys.getrefcount(arg)
self.assertEqual(arg_refcount_origin, arg_refcount_after)

def test_gh_99240_double_free(self):
expected_error = r'gh_99240_double_free\(\) argument 2 must be encoded string without null bytes, not str'
with self.assertRaisesRegex(TypeError, expected_error):
ac_tester.gh_99240_double_free('a', '\0b')

if __name__ == "__main__":
unittest.main()
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
Fix double-free bug in Argument Clinic ``str_converter`` by
extracting memory clean up to a new ``post_parsing`` section.
79 changes: 79 additions & 0 deletionsModules/_testclinic.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -551,6 +551,64 @@ str_converter_impl(PyObject *module, const char *a, const char *b,
}


/*[clinic input]
str_converter_encoding

a: str(encoding="idna")
b: str(encoding="idna", accept={bytes, bytearray, str})
c: str(encoding="idna", accept={bytes, bytearray, str}, zeroes=True)
/

[clinic start generated code]*/

static PyObject *
str_converter_encoding_impl(PyObject *module, char *a, char *b, char *c,
Py_ssize_t c_length)
/*[clinic end generated code: output=af68766049248a1c input=0c5cf5159d0e870d]*/
{
assert(!PyErr_Occurred());
PyObject *out[3] = {NULL,};
int i = 0;
PyObject *arg;

arg = PyUnicode_FromString(a);
assert(arg || PyErr_Occurred());
if (!arg) {
goto error;
}
out[i++] = arg;

arg = PyUnicode_FromString(b);
assert(arg || PyErr_Occurred());
if (!arg) {
goto error;
}
out[i++] = arg;

arg = PyUnicode_FromStringAndSize(c, c_length);
assert(arg || PyErr_Occurred());
if (!arg) {
goto error;
}
out[i++] = arg;

PyObject *tuple = PyTuple_New(3);
if (!tuple) {
goto error;
}
for (int j = 0; j < 3; j++) {
PyTuple_SET_ITEM(tuple, j, out[j]);
}
return tuple;

error:
for (int j = 0; j < i; j++) {
Py_DECREF(out[j]);
}
return NULL;
}


static PyObject *
bytes_from_buffer(Py_buffer *buf)
{
Expand DownExpand Up@@ -927,6 +985,25 @@ gh_99233_refcount_impl(PyObject *module, PyObject *args)
}


/*[clinic input]
gh_99240_double_free

a: str(encoding="idna")
b: str(encoding="idna")
/

Proof-of-concept of GH-99240 double-free bug.

[clinic start generated code]*/

static PyObject *
gh_99240_double_free_impl(PyObject *module, char *a, char *b)
/*[clinic end generated code: output=586dc714992fe2ed input=23db44aa91870fc7]*/
{
Py_RETURN_NONE;
}


static PyMethodDef tester_methods[] = {
TEST_EMPTY_FUNCTION_METHODDEF
OBJECTS_CONVERTER_METHODDEF
Expand All@@ -951,6 +1028,7 @@ static PyMethodDef tester_methods[] = {
DOUBLE_CONVERTER_METHODDEF
PY_COMPLEX_CONVERTER_METHODDEF
STR_CONVERTER_METHODDEF
STR_CONVERTER_ENCODING_METHODDEF
PY_BUFFER_CONVERTER_METHODDEF
KEYWORDS_METHODDEF
KEYWORDS_KWONLY_METHODDEF
Expand All@@ -970,6 +1048,7 @@ static PyMethodDef tester_methods[] = {
KEYWORD_ONLY_PARAMETER_METHODDEF
VARARG_AND_POSONLY_METHODDEF
GH_99233_REFCOUNT_METHODDEF
GH_99240_DOUBLE_FREE_METHODDEF
{NULL, NULL}
};

Expand Down
72 changes: 71 additions & 1 deletionModules/clinic/_testclinic.c.h
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

25 changes: 23 additions & 2 deletionsTools/clinic/clinic.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -348,6 +348,12 @@ def __init__(self):
# "goto exit" if there are any.
self.return_conversion = []

# The C statements required to do some operations
# after the end of parsing but before cleaning up.
# These operations may be, for example, memory deallocations which
# can only be done without any error happening during argument parsing.
self.post_parsing = []

# The C statements required to clean up after the impl call.
self.cleanup = []

Expand DownExpand Up@@ -820,6 +826,7 @@ def parser_body(prototype, *fields, declarations=''):
{modifications}
{return_value} = {c_basename}_impl({impl_arguments});
{return_conversion}
{post_parsing}

{exit_label}
{cleanup}
Expand DownExpand Up@@ -1460,6 +1467,7 @@ def render_function(self, clinic, f):
template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
template_dict['post_parsing'] = format_escape("".join(data.post_parsing).rstrip())
template_dict['cleanup'] = format_escape("".join(data.cleanup))
template_dict['return_value'] = data.return_value

Expand All@@ -1484,6 +1492,7 @@ def render_function(self, clinic, f):
return_conversion=template_dict['return_conversion'],
initializers=template_dict['initializers'],
modifications=template_dict['modifications'],
post_parsing=template_dict['post_parsing'],
cleanup=template_dict['cleanup'],
)

Expand DownExpand Up@@ -2725,6 +2734,10 @@ def _render_non_self(self, parameter, data):
# parse_arguments
self.parse_argument(data.parse_arguments)

# post_parsing
if post_parsing := self.post_parsing():
data.post_parsing.append('/* Post parse cleanup for ' + name + ' */\n' + post_parsing.rstrip() + '\n')

# cleanup
cleanup = self.cleanup()
if cleanup:
Expand DownExpand Up@@ -2820,6 +2833,14 @@ def modify(self):
"""
return ""

def post_parsing(self):
"""
The C statements required to do some operations after the end of parsing but before cleaning up.
Return a string containing this code indented at column 0.
If no operation is necessary, return an empty string.
"""
return ""

def cleanup(self):
"""
The C statements required to clean up after this variable.
Expand DownExpand Up@@ -3416,10 +3437,10 @@ def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
if NoneType in accept and self.c_default == "Py_None":
self.c_default = "NULL"

defcleanup(self):
defpost_parsing(self):
if self.encoding:
name = self.name
return"".join(["if (", name, ") {\nPyMem_FREE(",name, ");\n}\n"])
returnf"PyMem_FREE({name});\n"

def parse_arg(self, argname, displayname):
if self.format_unit == 's':
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp