Skip to content

Commit

Permalink
gh-99240: Fix double-free bug in Argument Clinic str_converter genera…
Browse files Browse the repository at this point in the history
…ted code (GH-99241)

Fix double-free bug mentioned at python/cpython#99240,
by moving memory clean up out of "exit" label.

Automerge-Triggered-By: GH:erlend-aasland
  • Loading branch information
colorfulappl committed Nov 24, 2022
1 parent c4882aa commit b4b59d1
Showing 1 changed file with 23 additions and 2 deletions.
25 changes: 23 additions & 2 deletions clinic-latest/clinic.py
Original file line number Diff line number Diff 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 Down Expand 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 Down Expand 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 Down Expand 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 Down Expand 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 Down Expand 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"

def cleanup(self):
def post_parsing(self):
if self.encoding:
name = self.name
return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
return f"PyMem_FREE({name});\n"

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

0 comments on commit b4b59d1

Please sign in to comment.