diff options
author | Ma Lin <animalize@users.noreply.github.com> | 2022-04-03 16:16:20 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-03 16:16:20 (GMT) |
commit | 6e3eee5c11b539e9aab39cff783acf57838c355a (patch) | |
tree | 29ee6720d249adfe5864ab9f09d7cb54d9f35238 /Modules | |
parent | b82cdd1dac9a9be52051abd90a1ce69236ac41f4 (diff) | |
download | cpython-6e3eee5c11b539e9aab39cff783acf57838c355a.zip cpython-6e3eee5c11b539e9aab39cff783acf57838c355a.tar.gz cpython-6e3eee5c11b539e9aab39cff783acf57838c355a.tar.bz2 |
bpo-23689: re module, fix memory leak when a match is terminated by a signal or memory allocation failure (GH-32283)
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_sre.c | 65 | ||||
-rw-r--r-- | Modules/clinic/_sre.c.h | 27 | ||||
-rw-r--r-- | Modules/sre.h | 4 | ||||
-rw-r--r-- | Modules/sre_constants.h | 2 | ||||
-rw-r--r-- | Modules/sre_lib.h | 31 |
5 files changed, 83 insertions, 46 deletions
diff --git a/Modules/_sre.c b/Modules/_sre.c index 48193f8..506363d 100644 --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -427,6 +427,12 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, state->lastmark = -1; state->lastindex = -1; + state->repeats_array = PyMem_New(SRE_REPEAT, pattern->repeat_count); + if (!state->repeats_array) { + PyErr_NoMemory(); + goto err; + } + state->buffer.buf = NULL; ptr = getstring(string, &length, &isbytes, &charsize, &state->buffer); if (!ptr) @@ -476,6 +482,9 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, safely casted to `void*`, see bpo-39943 for details. */ PyMem_Free((void*) state->mark); state->mark = NULL; + PyMem_Free(state->repeats_array); + state->repeats_array = NULL; + if (state->buffer.buf) PyBuffer_Release(&state->buffer); return NULL; @@ -491,6 +500,8 @@ state_fini(SRE_STATE* state) /* See above PyMem_Del for why we explicitly cast here. */ PyMem_Free((void*) state->mark); state->mark = NULL; + PyMem_Free(state->repeats_array); + state->repeats_array = NULL; } /* calculate offset from start of string */ @@ -1407,14 +1418,15 @@ _sre.compile groups: Py_ssize_t groupindex: object(subclass_of='&PyDict_Type') indexgroup: object(subclass_of='&PyTuple_Type') + repeat_count: Py_ssize_t [clinic start generated code]*/ static PyObject * _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, PyObject *code, Py_ssize_t groups, PyObject *groupindex, - PyObject *indexgroup) -/*[clinic end generated code: output=ef9c2b3693776404 input=0a68476dbbe5db30]*/ + PyObject *indexgroup, Py_ssize_t repeat_count) +/*[clinic end generated code: output=922af562d51b1657 input=77e39c322501ec2a]*/ { /* "compile" pattern descriptor to pattern object */ @@ -1472,8 +1484,8 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, self->pattern = pattern; self->flags = flags; - self->groups = groups; + self->repeat_count = repeat_count; if (PyDict_GET_SIZE(groupindex) > 0) { Py_INCREF(groupindex); @@ -1645,7 +1657,7 @@ _validate_charset(SRE_CODE *code, SRE_CODE *end) } static int -_validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) +_validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) { /* Some variables are manipulated by the macros above */ SRE_CODE op; @@ -1666,8 +1678,8 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) sre_match() code is robust even if they don't, and the worst you can get is nonsensical match results. */ GET_ARG; - if (arg > 2 * (size_t)groups + 1) { - VTRACE(("arg=%d, groups=%d\n", (int)arg, (int)groups)); + if (arg > 2 * (size_t)self->groups + 1) { + VTRACE(("arg=%d, groups=%d\n", (int)arg, (int)self->groups)); FAIL; } break; @@ -1796,7 +1808,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) if (skip == 0) break; /* Stop 2 before the end; we check the JUMP below */ - if (!_validate_inner(code, code+skip-3, groups)) + if (!_validate_inner(code, code+skip-3, self)) FAIL; code += skip-3; /* Check that it ends with a JUMP, and that each JUMP @@ -1825,7 +1837,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) FAIL; if (max > SRE_MAXREPEAT) FAIL; - if (!_validate_inner(code, code+skip-4, groups)) + if (!_validate_inner(code, code+skip-4, self)) FAIL; code += skip-4; GET_OP; @@ -1837,7 +1849,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) case SRE_OP_REPEAT: case SRE_OP_POSSESSIVE_REPEAT: { - SRE_CODE op1 = op, min, max; + SRE_CODE op1 = op, min, max, repeat_index; GET_SKIP; GET_ARG; min = arg; GET_ARG; max = arg; @@ -1845,9 +1857,17 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) FAIL; if (max > SRE_MAXREPEAT) FAIL; - if (!_validate_inner(code, code+skip-3, groups)) + if (op1 == SRE_OP_REPEAT) { + GET_ARG; repeat_index = arg; + if (repeat_index >= (size_t)self->repeat_count) + FAIL; + skip -= 4; + } else { + skip -= 3; + } + if (!_validate_inner(code, code+skip, self)) FAIL; - code += skip-3; + code += skip; GET_OP; if (op1 == SRE_OP_POSSESSIVE_REPEAT) { if (op != SRE_OP_SUCCESS) @@ -1863,7 +1883,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) case SRE_OP_ATOMIC_GROUP: { GET_SKIP; - if (!_validate_inner(code, code+skip-2, groups)) + if (!_validate_inner(code, code+skip-2, self)) FAIL; code += skip-2; GET_OP; @@ -1877,7 +1897,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) case SRE_OP_GROUPREF_UNI_IGNORE: case SRE_OP_GROUPREF_LOC_IGNORE: GET_ARG; - if (arg >= (size_t)groups) + if (arg >= (size_t)self->groups) FAIL; break; @@ -1886,7 +1906,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) 'group' is either an integer group number or a group name, 'then' and 'else' are sub-regexes, and 'else' is optional. */ GET_ARG; - if (arg >= (size_t)groups) + if (arg >= (size_t)self->groups) FAIL; GET_SKIP_ADJ(1); code--; /* The skip is relative to the first arg! */ @@ -1919,17 +1939,17 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) code[skip-3] == SRE_OP_JUMP) { VTRACE(("both then and else parts present\n")); - if (!_validate_inner(code+1, code+skip-3, groups)) + if (!_validate_inner(code+1, code+skip-3, self)) FAIL; code += skip-2; /* Position after JUMP, at <skipno> */ GET_SKIP; - if (!_validate_inner(code, code+skip-1, groups)) + if (!_validate_inner(code, code+skip-1, self)) FAIL; code += skip-1; } else { VTRACE(("only a then part present\n")); - if (!_validate_inner(code+1, code+skip-1, groups)) + if (!_validate_inner(code+1, code+skip-1, self)) FAIL; code += skip-1; } @@ -1943,7 +1963,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) if (arg & 0x80000000) FAIL; /* Width too large */ /* Stop 1 before the end; we check the SUCCESS below */ - if (!_validate_inner(code+1, code+skip-2, groups)) + if (!_validate_inner(code+1, code+skip-2, self)) FAIL; code += skip-2; GET_OP; @@ -1962,18 +1982,19 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) } static int -_validate_outer(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) +_validate_outer(SRE_CODE *code, SRE_CODE *end, PatternObject *self) { - if (groups < 0 || (size_t)groups > SRE_MAXGROUPS || + if (self->groups < 0 || (size_t)self->groups > SRE_MAXGROUPS || + self->repeat_count < 0 || code >= end || end[-1] != SRE_OP_SUCCESS) FAIL; - return _validate_inner(code, end-1, groups); + return _validate_inner(code, end-1, self); } static int _validate(PatternObject *self) { - if (!_validate_outer(self->code, self->code+self->codesize, self->groups)) + if (!_validate_outer(self->code, self->code+self->codesize, self)) { PyErr_SetString(PyExc_RuntimeError, "invalid SRE code"); return 0; diff --git a/Modules/clinic/_sre.c.h b/Modules/clinic/_sre.c.h index 72d772c..34cbe21 100644 --- a/Modules/clinic/_sre.c.h +++ b/Modules/clinic/_sre.c.h @@ -544,7 +544,7 @@ PyDoc_STRVAR(_sre_SRE_Pattern___deepcopy____doc__, PyDoc_STRVAR(_sre_compile__doc__, "compile($module, /, pattern, flags, code, groups, groupindex,\n" -" indexgroup)\n" +" indexgroup, repeat_count)\n" "--\n" "\n"); @@ -554,23 +554,24 @@ PyDoc_STRVAR(_sre_compile__doc__, static PyObject * _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, PyObject *code, Py_ssize_t groups, PyObject *groupindex, - PyObject *indexgroup); + PyObject *indexgroup, Py_ssize_t repeat_count); static PyObject * _sre_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; - static const char * const _keywords[] = {"pattern", "flags", "code", "groups", "groupindex", "indexgroup", NULL}; + static const char * const _keywords[] = {"pattern", "flags", "code", "groups", "groupindex", "indexgroup", "repeat_count", NULL}; static _PyArg_Parser _parser = {NULL, _keywords, "compile", 0}; - PyObject *argsbuf[6]; + PyObject *argsbuf[7]; PyObject *pattern; int flags; PyObject *code; Py_ssize_t groups; PyObject *groupindex; PyObject *indexgroup; + Py_ssize_t repeat_count; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 6, 6, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 7, 7, 0, argsbuf); if (!args) { goto exit; } @@ -606,7 +607,19 @@ _sre_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject goto exit; } indexgroup = args[5]; - return_value = _sre_compile_impl(module, pattern, flags, code, groups, groupindex, indexgroup); + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[6]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + repeat_count = ival; + } + return_value = _sre_compile_impl(module, pattern, flags, code, groups, groupindex, indexgroup, repeat_count); exit: return return_value; @@ -910,4 +923,4 @@ _sre_SRE_Scanner_search(ScannerObject *self, PyTypeObject *cls, PyObject *const exit: return return_value; } -/*[clinic end generated code: output=518f7bb775c1184f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9d7510a57a157a38 input=a9049054013a1b77]*/ diff --git a/Modules/sre.h b/Modules/sre.h index 785adbd..e2c5277 100644 --- a/Modules/sre.h +++ b/Modules/sre.h @@ -29,6 +29,8 @@ typedef struct { Py_ssize_t groups; /* must be first! */ PyObject* groupindex; /* dict */ PyObject* indexgroup; /* tuple */ + /* the number of REPEATs */ + Py_ssize_t repeat_count; /* compatibility */ PyObject* pattern; /* pattern source (or None) */ int flags; /* flags used when compiling pattern source */ @@ -83,6 +85,8 @@ typedef struct { size_t data_stack_base; /* current repeat context */ SRE_REPEAT *repeat; + /* repeat contexts array */ + SRE_REPEAT *repeats_array; } SRE_STATE; typedef struct { diff --git a/Modules/sre_constants.h b/Modules/sre_constants.h index 45395dc..8b24949 100644 --- a/Modules/sre_constants.h +++ b/Modules/sre_constants.h @@ -11,7 +11,7 @@ * See the _sre.c file for information on usage and redistribution. */ -#define SRE_MAGIC 20220318 +#define SRE_MAGIC 20220402 #define SRE_OP_FAILURE 0 #define SRE_OP_SUCCESS 1 #define SRE_OP_ANY 2 diff --git a/Modules/sre_lib.h b/Modules/sre_lib.h index 8e4e714..1cc926d 100644 --- a/Modules/sre_lib.h +++ b/Modules/sre_lib.h @@ -1032,16 +1032,14 @@ entrance: case SRE_OP_REPEAT: /* create repeat context. all the hard work is done by the UNTIL operator (MAX_UNTIL, MIN_UNTIL) */ - /* <REPEAT> <skip> <1=min> <2=max> item <UNTIL> tail */ - TRACE(("|%p|%p|REPEAT %d %d\n", ctx->pattern, ctx->ptr, - ctx->pattern[1], ctx->pattern[2])); + /* <REPEAT> <skip> <1=min> <2=max> + <3=repeat_index> item <UNTIL> tail */ + TRACE(("|%p|%p|REPEAT %d %d %d\n", ctx->pattern, ctx->ptr, + ctx->pattern[1], ctx->pattern[2], ctx->pattern[3])); + + /* install repeat context */ + ctx->u.rep = &state->repeats_array[ctx->pattern[3]]; - /* install new repeat context */ - ctx->u.rep = (SRE_REPEAT*) PyObject_Malloc(sizeof(*ctx->u.rep)); - if (!ctx->u.rep) { - PyErr_NoMemory(); - RETURN_FAILURE; - } ctx->u.rep->count = -1; ctx->u.rep->pattern = ctx->pattern; ctx->u.rep->prev = state->repeat; @@ -1051,7 +1049,6 @@ entrance: state->ptr = ctx->ptr; DO_JUMP(JUMP_REPEAT, jump_repeat, ctx->pattern+ctx->pattern[0]); state->repeat = ctx->u.rep->prev; - PyObject_Free(ctx->u.rep); if (ret) { RETURN_ON_ERROR(ret); @@ -1061,7 +1058,8 @@ entrance: case SRE_OP_MAX_UNTIL: /* maximizing repeat */ - /* <REPEAT> <skip> <1=min> <2=max> item <MAX_UNTIL> tail */ + /* <REPEAT> <skip> <1=min> <2=max> + <3=repeat_index> item <MAX_UNTIL> tail */ /* FIXME: we probably need to deal with zero-width matches in here... */ @@ -1081,7 +1079,7 @@ entrance: /* not enough matches */ ctx->u.rep->count = ctx->count; DO_JUMP(JUMP_MAX_UNTIL_1, jump_max_until_1, - ctx->u.rep->pattern+3); + ctx->u.rep->pattern+4); if (ret) { RETURN_ON_ERROR(ret); RETURN_SUCCESS; @@ -1103,7 +1101,7 @@ entrance: DATA_PUSH(&ctx->u.rep->last_ptr); ctx->u.rep->last_ptr = state->ptr; DO_JUMP(JUMP_MAX_UNTIL_2, jump_max_until_2, - ctx->u.rep->pattern+3); + ctx->u.rep->pattern+4); DATA_POP(&ctx->u.rep->last_ptr); if (ret) { MARK_POP_DISCARD(ctx->lastmark); @@ -1128,7 +1126,8 @@ entrance: case SRE_OP_MIN_UNTIL: /* minimizing repeat */ - /* <REPEAT> <skip> <1=min> <2=max> item <MIN_UNTIL> tail */ + /* <REPEAT> <skip> <1=min> <2=max> + <3=repeat_index> item <MIN_UNTIL> tail */ ctx->u.rep = state->repeat; if (!ctx->u.rep) @@ -1145,7 +1144,7 @@ entrance: /* not enough matches */ ctx->u.rep->count = ctx->count; DO_JUMP(JUMP_MIN_UNTIL_1, jump_min_until_1, - ctx->u.rep->pattern+3); + ctx->u.rep->pattern+4); if (ret) { RETURN_ON_ERROR(ret); RETURN_SUCCESS; @@ -1188,7 +1187,7 @@ entrance: DATA_PUSH(&ctx->u.rep->last_ptr); ctx->u.rep->last_ptr = state->ptr; DO_JUMP(JUMP_MIN_UNTIL_3,jump_min_until_3, - ctx->u.rep->pattern+3); + ctx->u.rep->pattern+4); DATA_POP(&ctx->u.rep->last_ptr); if (ret) { RETURN_ON_ERROR(ret); |