mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
bpo-23689: re module, fix memory leak when a match is terminated by a signal or memory allocation failure (GH-32283)
This commit is contained in:
parent
b82cdd1dac
commit
6e3eee5c11
9 changed files with 151 additions and 71 deletions
|
@ -67,14 +67,21 @@ _equivalences = (
|
|||
_ignorecase_fixes = {i: tuple(j for j in t if i != j)
|
||||
for t in _equivalences for i in t}
|
||||
|
||||
class _CompileData:
|
||||
__slots__ = ('code', 'repeat_count')
|
||||
def __init__(self):
|
||||
self.code = []
|
||||
self.repeat_count = 0
|
||||
|
||||
def _combine_flags(flags, add_flags, del_flags,
|
||||
TYPE_FLAGS=_parser.TYPE_FLAGS):
|
||||
if add_flags & TYPE_FLAGS:
|
||||
flags &= ~TYPE_FLAGS
|
||||
return (flags | add_flags) & ~del_flags
|
||||
|
||||
def _compile(code, pattern, flags):
|
||||
def _compile(data, pattern, flags):
|
||||
# internal: compile a (sub)pattern
|
||||
code = data.code
|
||||
emit = code.append
|
||||
_len = len
|
||||
LITERAL_CODES = _LITERAL_CODES
|
||||
|
@ -147,7 +154,7 @@ def _compile(code, pattern, flags):
|
|||
skip = _len(code); emit(0)
|
||||
emit(av[0])
|
||||
emit(av[1])
|
||||
_compile(code, av[2], flags)
|
||||
_compile(data, av[2], flags)
|
||||
emit(SUCCESS)
|
||||
code[skip] = _len(code) - skip
|
||||
else:
|
||||
|
@ -155,7 +162,11 @@ def _compile(code, pattern, flags):
|
|||
skip = _len(code); emit(0)
|
||||
emit(av[0])
|
||||
emit(av[1])
|
||||
_compile(code, av[2], flags)
|
||||
# now op is in (MIN_REPEAT, MAX_REPEAT, POSSESSIVE_REPEAT)
|
||||
if op != POSSESSIVE_REPEAT:
|
||||
emit(data.repeat_count)
|
||||
data.repeat_count += 1
|
||||
_compile(data, av[2], flags)
|
||||
code[skip] = _len(code) - skip
|
||||
emit(REPEATING_CODES[op][1])
|
||||
elif op is SUBPATTERN:
|
||||
|
@ -164,7 +175,7 @@ def _compile(code, pattern, flags):
|
|||
emit(MARK)
|
||||
emit((group-1)*2)
|
||||
# _compile_info(code, p, _combine_flags(flags, add_flags, del_flags))
|
||||
_compile(code, p, _combine_flags(flags, add_flags, del_flags))
|
||||
_compile(data, p, _combine_flags(flags, add_flags, del_flags))
|
||||
if group:
|
||||
emit(MARK)
|
||||
emit((group-1)*2+1)
|
||||
|
@ -176,7 +187,7 @@ def _compile(code, pattern, flags):
|
|||
# pop their stack if they reach it
|
||||
emit(ATOMIC_GROUP)
|
||||
skip = _len(code); emit(0)
|
||||
_compile(code, av, flags)
|
||||
_compile(data, av, flags)
|
||||
emit(SUCCESS)
|
||||
code[skip] = _len(code) - skip
|
||||
elif op in SUCCESS_CODES:
|
||||
|
@ -191,13 +202,13 @@ def _compile(code, pattern, flags):
|
|||
if lo != hi:
|
||||
raise error("look-behind requires fixed-width pattern")
|
||||
emit(lo) # look behind
|
||||
_compile(code, av[1], flags)
|
||||
_compile(data, av[1], flags)
|
||||
emit(SUCCESS)
|
||||
code[skip] = _len(code) - skip
|
||||
elif op is CALL:
|
||||
emit(op)
|
||||
skip = _len(code); emit(0)
|
||||
_compile(code, av, flags)
|
||||
_compile(data, av, flags)
|
||||
emit(SUCCESS)
|
||||
code[skip] = _len(code) - skip
|
||||
elif op is AT:
|
||||
|
@ -216,7 +227,7 @@ def _compile(code, pattern, flags):
|
|||
for av in av[1]:
|
||||
skip = _len(code); emit(0)
|
||||
# _compile_info(code, av, flags)
|
||||
_compile(code, av, flags)
|
||||
_compile(data, av, flags)
|
||||
emit(JUMP)
|
||||
tailappend(_len(code)); emit(0)
|
||||
code[skip] = _len(code) - skip
|
||||
|
@ -244,12 +255,12 @@ def _compile(code, pattern, flags):
|
|||
emit(op)
|
||||
emit(av[0]-1)
|
||||
skipyes = _len(code); emit(0)
|
||||
_compile(code, av[1], flags)
|
||||
_compile(data, av[1], flags)
|
||||
if av[2]:
|
||||
emit(JUMP)
|
||||
skipno = _len(code); emit(0)
|
||||
code[skipyes] = _len(code) - skipyes + 1
|
||||
_compile(code, av[2], flags)
|
||||
_compile(data, av[2], flags)
|
||||
code[skipno] = _len(code) - skipno
|
||||
else:
|
||||
code[skipyes] = _len(code) - skipyes + 1
|
||||
|
@ -608,17 +619,17 @@ def isstring(obj):
|
|||
def _code(p, flags):
|
||||
|
||||
flags = p.state.flags | flags
|
||||
code = []
|
||||
data = _CompileData()
|
||||
|
||||
# compile info block
|
||||
_compile_info(code, p, flags)
|
||||
_compile_info(data.code, p, flags)
|
||||
|
||||
# compile the pattern
|
||||
_compile(code, p.data, flags)
|
||||
_compile(data, p.data, flags)
|
||||
|
||||
code.append(SUCCESS)
|
||||
data.code.append(SUCCESS)
|
||||
|
||||
return code
|
||||
return data
|
||||
|
||||
def _hex_code(code):
|
||||
return '[%s]' % ', '.join('%#0*x' % (_sre.CODESIZE*2+2, x) for x in code)
|
||||
|
@ -719,7 +730,7 @@ def dis(code):
|
|||
else:
|
||||
print_(FAILURE)
|
||||
i += 1
|
||||
elif op in (REPEAT, REPEAT_ONE, MIN_REPEAT_ONE,
|
||||
elif op in (REPEAT_ONE, MIN_REPEAT_ONE,
|
||||
POSSESSIVE_REPEAT, POSSESSIVE_REPEAT_ONE):
|
||||
skip, min, max = code[i: i+3]
|
||||
if max == MAXREPEAT:
|
||||
|
@ -727,6 +738,13 @@ def dis(code):
|
|||
print_(op, skip, min, max, to=i+skip)
|
||||
dis_(i+3, i+skip)
|
||||
i += skip
|
||||
elif op is REPEAT:
|
||||
skip, min, max, repeat_index = code[i: i+4]
|
||||
if max == MAXREPEAT:
|
||||
max = 'MAXREPEAT'
|
||||
print_(op, skip, min, max, repeat_index, to=i+skip)
|
||||
dis_(i+4, i+skip)
|
||||
i += skip
|
||||
elif op is GROUPREF_EXISTS:
|
||||
arg, skip = code[i: i+2]
|
||||
print_(op, arg, skip, to=i+skip)
|
||||
|
@ -781,11 +799,11 @@ def compile(p, flags=0):
|
|||
else:
|
||||
pattern = None
|
||||
|
||||
code = _code(p, flags)
|
||||
data = _code(p, flags)
|
||||
|
||||
if flags & SRE_FLAG_DEBUG:
|
||||
print()
|
||||
dis(code)
|
||||
dis(data.code)
|
||||
|
||||
# map in either direction
|
||||
groupindex = p.state.groupdict
|
||||
|
@ -794,7 +812,6 @@ def compile(p, flags=0):
|
|||
indexgroup[i] = k
|
||||
|
||||
return _sre.compile(
|
||||
pattern, flags | p.state.flags, code,
|
||||
p.state.groups-1,
|
||||
groupindex, tuple(indexgroup)
|
||||
)
|
||||
pattern, flags | p.state.flags, data.code,
|
||||
p.state.groups-1, groupindex, tuple(indexgroup),
|
||||
data.repeat_count)
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
# update when constants are added or removed
|
||||
|
||||
MAGIC = 20220318
|
||||
MAGIC = 20220402
|
||||
|
||||
from _sre import MAXREPEAT, MAXGROUPS
|
||||
|
||||
|
|
|
@ -1643,9 +1643,12 @@ class ReTests(unittest.TestCase):
|
|||
long_overflow = 2**128
|
||||
self.assertRaises(TypeError, re.finditer, "a", {})
|
||||
with self.assertRaises(OverflowError):
|
||||
_sre.compile("abc", 0, [long_overflow], 0, {}, ())
|
||||
_sre.compile("abc", 0, [long_overflow], 0, {}, (), 0)
|
||||
with self.assertRaises(TypeError):
|
||||
_sre.compile({}, 0, [], 0, [], [])
|
||||
_sre.compile({}, 0, [], 0, [], [], 0)
|
||||
with self.assertRaises(RuntimeError):
|
||||
# invalid repeat_count -1
|
||||
_sre.compile("abc", 0, [1], 0, {}, (), -1)
|
||||
|
||||
def test_search_dot_unicode(self):
|
||||
self.assertTrue(re.search("123.*-", '123abc-'))
|
||||
|
@ -2334,6 +2337,27 @@ POSSESSIVE_REPEAT 0 1
|
|||
14. SUCCESS
|
||||
''')
|
||||
|
||||
def test_repeat_index(self):
|
||||
self.assertEqual(get_debug_out(r'(?:ab)*?(?:cd)*'), '''\
|
||||
MIN_REPEAT 0 MAXREPEAT
|
||||
LITERAL 97
|
||||
LITERAL 98
|
||||
MAX_REPEAT 0 MAXREPEAT
|
||||
LITERAL 99
|
||||
LITERAL 100
|
||||
|
||||
0. INFO 4 0b0 0 MAXREPEAT (to 5)
|
||||
5: REPEAT 8 0 MAXREPEAT 0 (to 14)
|
||||
10. LITERAL 0x61 ('a')
|
||||
12. LITERAL 0x62 ('b')
|
||||
14: MIN_UNTIL
|
||||
15. REPEAT 8 0 MAXREPEAT 1 (to 24)
|
||||
20. LITERAL 0x63 ('c')
|
||||
22. LITERAL 0x64 ('d')
|
||||
24: MAX_UNTIL
|
||||
25. SUCCESS
|
||||
''')
|
||||
|
||||
|
||||
class PatternReprTests(unittest.TestCase):
|
||||
def check(self, pattern, expected):
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
:mod:`re` module: fix memory leak when a match is terminated by a signal or
|
||||
memory allocation failure. Patch by Ma Lin.
|
|
@ -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;
|
||||
code += skip-3;
|
||||
skip -= 4;
|
||||
} else {
|
||||
skip -= 3;
|
||||
}
|
||||
if (!_validate_inner(code, code+skip, self))
|
||||
FAIL;
|
||||
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;
|
||||
|
|
27
Modules/clinic/_sre.c.h
generated
27
Modules/clinic/_sre.c.h
generated
|
@ -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]*/
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue