diff options
author | Lysandros Nikolaou <lisandrosnik@gmail.com> | 2020-05-17 03:19:23 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-17 03:19:23 (GMT) |
commit | 2c8cd06afe8e0abb52367f85978f19b88e2df53e (patch) | |
tree | ea90af6b2975c27c85f491e2eda51911c15c3d6f /Tools/peg_generator | |
parent | 6341fc7257d89d798675ad6e425f7eb0b6f2b4bb (diff) | |
download | cpython-2c8cd06afe8e0abb52367f85978f19b88e2df53e.zip cpython-2c8cd06afe8e0abb52367f85978f19b88e2df53e.tar.gz cpython-2c8cd06afe8e0abb52367f85978f19b88e2df53e.tar.bz2 |
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>
Diffstat (limited to 'Tools/peg_generator')
-rw-r--r-- | Tools/peg_generator/pegen/c_generator.py | 33 |
1 files changed, 12 insertions, 21 deletions
diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py index 6c9aa3f..8f9972b 100644 --- a/Tools/peg_generator/pegen/c_generator.py +++ b/Tools/peg_generator/pegen/c_generator.py @@ -320,24 +320,21 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): def out_of_memory_return( self, expr: str, - returnval: str, - message: str = "Parser out of memory", cleanup_code: Optional[str] = None, ) -> None: self.print(f"if ({expr}) {{") with self.indent(): - self.print(f'PyErr_Format(PyExc_MemoryError, "{message}");') if cleanup_code is not None: 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"}}") - def out_of_memory_goto( - self, expr: str, goto_target: str, message: str = "Parser out of memory" - ) -> None: + def out_of_memory_goto(self, expr: str, goto_target: str) -> None: self.print(f"if ({expr}) {{") with self.indent(): - self.print(f'PyErr_Format(PyExc_MemoryError, "{message}");') + self.print("PyErr_NoMemory();") self.print(f"goto {goto_target};") self.print(f"}}") @@ -487,7 +484,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): rhs, is_loop=False, is_gather=node.is_gather(), - rulename=node.name if memoize else None, + rulename=node.name, ) if self.debug: 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 _start_mark = p->mark;") 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 _n = 0;") if any(alt.action and "EXTRA" in alt.action for alt in rhs.alts): @@ -524,7 +521,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): rhs, is_loop=True, is_gather=node.is_gather(), - rulename=node.name if memoize else None, + rulename=node.name, ) if is_repeat1: self.print("if (_n == 0 || p->error_indicator) {") @@ -533,12 +530,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.print("return NULL;") self.print("}") self.print("asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);") - self.out_of_memory_return( - "!_seq", - "NULL", - message=f"asdl_seq_new {node.name}", - cleanup_code="PyMem_Free(_children);", - ) + self.out_of_memory_return(f"!_seq", cleanup_code="PyMem_Free(_children);") self.print("for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);") self.print("PyMem_Free(_children);") if node.name: @@ -682,10 +674,9 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.print("if (_n == _children_capacity) {") with self.indent(): self.print("_children_capacity *= 2;") - self.print( - "_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));" - ) - self.out_of_memory_return(f"!_children", "NULL", message=f"realloc {rulename}") + self.print("void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));") + self.out_of_memory_return(f"!_new_children") + self.print("_children = _new_children;") self.print("}") self.print("_children[_n++] = _res;") self.print("_mark = p->mark;") |