mirror of https://github.com/python/cpython
bpo-40334: Improvements to error-handling code in the PEG parser (GH-20003)
The following improvements are implemented in this commit: - `p->error_indicator` is set, in case malloc or realloc fail. - Avoid memory leaks in the case that realloc fails. - Call `PyErr_NoMemory()` instead of `PyErr_Format()`, because it requires no memory. Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
This commit is contained in:
parent
6341fc7257
commit
2c8cd06afe
1022
Parser/pegen/parse.c
1022
Parser/pegen/parse.c
File diff suppressed because it is too large
Load Diff
|
@ -320,24 +320,21 @@ class CParserGenerator(ParserGenerator, GrammarVisitor):
|
||||||
def out_of_memory_return(
|
def out_of_memory_return(
|
||||||
self,
|
self,
|
||||||
expr: str,
|
expr: str,
|
||||||
returnval: str,
|
|
||||||
message: str = "Parser out of memory",
|
|
||||||
cleanup_code: Optional[str] = None,
|
cleanup_code: Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.print(f"if ({expr}) {{")
|
self.print(f"if ({expr}) {{")
|
||||||
with self.indent():
|
with self.indent():
|
||||||
self.print(f'PyErr_Format(PyExc_MemoryError, "{message}");')
|
|
||||||
if cleanup_code is not None:
|
if cleanup_code is not None:
|
||||||
self.print(cleanup_code)
|
self.print(cleanup_code)
|
||||||
self.print(f"return {returnval};")
|
self.print("p->error_indicator = 1;")
|
||||||
|
self.print("PyErr_NoMemory();");
|
||||||
|
self.print("return NULL;")
|
||||||
self.print(f"}}")
|
self.print(f"}}")
|
||||||
|
|
||||||
def out_of_memory_goto(
|
def out_of_memory_goto(self, expr: str, goto_target: str) -> None:
|
||||||
self, expr: str, goto_target: str, message: str = "Parser out of memory"
|
|
||||||
) -> None:
|
|
||||||
self.print(f"if ({expr}) {{")
|
self.print(f"if ({expr}) {{")
|
||||||
with self.indent():
|
with self.indent():
|
||||||
self.print(f'PyErr_Format(PyExc_MemoryError, "{message}");')
|
self.print("PyErr_NoMemory();")
|
||||||
self.print(f"goto {goto_target};")
|
self.print(f"goto {goto_target};")
|
||||||
self.print(f"}}")
|
self.print(f"}}")
|
||||||
|
|
||||||
|
@ -487,7 +484,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor):
|
||||||
rhs,
|
rhs,
|
||||||
is_loop=False,
|
is_loop=False,
|
||||||
is_gather=node.is_gather(),
|
is_gather=node.is_gather(),
|
||||||
rulename=node.name if memoize else None,
|
rulename=node.name,
|
||||||
)
|
)
|
||||||
if self.debug:
|
if self.debug:
|
||||||
self.print('fprintf(stderr, "Fail at %d: {node.name}\\n", p->mark);')
|
self.print('fprintf(stderr, "Fail at %d: {node.name}\\n", p->mark);')
|
||||||
|
@ -515,7 +512,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor):
|
||||||
self.print("int _mark = p->mark;")
|
self.print("int _mark = p->mark;")
|
||||||
self.print("int _start_mark = p->mark;")
|
self.print("int _start_mark = p->mark;")
|
||||||
self.print("void **_children = PyMem_Malloc(sizeof(void *));")
|
self.print("void **_children = PyMem_Malloc(sizeof(void *));")
|
||||||
self.out_of_memory_return(f"!_children", "NULL")
|
self.out_of_memory_return(f"!_children")
|
||||||
self.print("ssize_t _children_capacity = 1;")
|
self.print("ssize_t _children_capacity = 1;")
|
||||||
self.print("ssize_t _n = 0;")
|
self.print("ssize_t _n = 0;")
|
||||||
if any(alt.action and "EXTRA" in alt.action for alt in rhs.alts):
|
if any(alt.action and "EXTRA" in alt.action for alt in rhs.alts):
|
||||||
|
@ -524,7 +521,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor):
|
||||||
rhs,
|
rhs,
|
||||||
is_loop=True,
|
is_loop=True,
|
||||||
is_gather=node.is_gather(),
|
is_gather=node.is_gather(),
|
||||||
rulename=node.name if memoize else None,
|
rulename=node.name,
|
||||||
)
|
)
|
||||||
if is_repeat1:
|
if is_repeat1:
|
||||||
self.print("if (_n == 0 || p->error_indicator) {")
|
self.print("if (_n == 0 || p->error_indicator) {")
|
||||||
|
@ -533,12 +530,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor):
|
||||||
self.print("return NULL;")
|
self.print("return NULL;")
|
||||||
self.print("}")
|
self.print("}")
|
||||||
self.print("asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);")
|
self.print("asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);")
|
||||||
self.out_of_memory_return(
|
self.out_of_memory_return(f"!_seq", cleanup_code="PyMem_Free(_children);")
|
||||||
"!_seq",
|
|
||||||
"NULL",
|
|
||||||
message=f"asdl_seq_new {node.name}",
|
|
||||||
cleanup_code="PyMem_Free(_children);",
|
|
||||||
)
|
|
||||||
self.print("for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);")
|
self.print("for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);")
|
||||||
self.print("PyMem_Free(_children);")
|
self.print("PyMem_Free(_children);")
|
||||||
if node.name:
|
if node.name:
|
||||||
|
@ -682,10 +674,9 @@ class CParserGenerator(ParserGenerator, GrammarVisitor):
|
||||||
self.print("if (_n == _children_capacity) {")
|
self.print("if (_n == _children_capacity) {")
|
||||||
with self.indent():
|
with self.indent():
|
||||||
self.print("_children_capacity *= 2;")
|
self.print("_children_capacity *= 2;")
|
||||||
self.print(
|
self.print("void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));")
|
||||||
"_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));"
|
self.out_of_memory_return(f"!_new_children")
|
||||||
)
|
self.print("_children = _new_children;")
|
||||||
self.out_of_memory_return(f"!_children", "NULL", message=f"realloc {rulename}")
|
|
||||||
self.print("}")
|
self.print("}")
|
||||||
self.print("_children[_n++] = _res;")
|
self.print("_children[_n++] = _res;")
|
||||||
self.print("_mark = p->mark;")
|
self.print("_mark = p->mark;")
|
||||||
|
|
Loading…
Reference in New Issue