Commit e48944b6 authored by Benjamin Peterson's avatar Benjamin Peterson

keep the buffer object around while we're using it (closes #14212)

parent 30b8e546
from test.support import verbose, run_unittest from test.support import verbose, run_unittest, gc_collect
import io
import re import re
from re import Scanner from re import Scanner
import sys import sys
...@@ -16,6 +17,17 @@ import unittest ...@@ -16,6 +17,17 @@ import unittest
class ReTests(unittest.TestCase): class ReTests(unittest.TestCase):
def test_keep_buffer(self):
# See bug 14212
b = bytearray(b'x')
it = re.finditer(b'a', b)
with self.assertRaises(BufferError):
b.extend(b'x'*400)
list(it)
del it
gc_collect()
b.extend(b'x'*400)
def test_weakref(self): def test_weakref(self):
s = 'QabbbcR' s = 'QabbbcR'
x = re.compile('ab+c') x = re.compile('ab+c')
......
...@@ -549,6 +549,9 @@ Tests ...@@ -549,6 +549,9 @@ Tests
Extension Modules Extension Modules
----------------- -----------------
- Issue #14212: The re module didn't retain a reference to buffers it was
scanning, resulting in segfaults.
- Issue #13840: The error message produced by ctypes.create_string_buffer - Issue #13840: The error message produced by ctypes.create_string_buffer
when given a Unicode string has been fixed. when given a Unicode string has been fixed.
......
...@@ -1664,7 +1664,7 @@ state_reset(SRE_STATE* state) ...@@ -1664,7 +1664,7 @@ state_reset(SRE_STATE* state)
} }
static void* static void*
getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize) getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize, Py_buffer *view)
{ {
/* given a python object, return a data pointer, a length (in /* given a python object, return a data pointer, a length (in
characters), and a character size. return NULL if the object characters), and a character size. return NULL if the object
...@@ -1674,7 +1674,6 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize) ...@@ -1674,7 +1674,6 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize)
Py_ssize_t size, bytes; Py_ssize_t size, bytes;
int charsize; int charsize;
void* ptr; void* ptr;
Py_buffer view;
/* Unicode objects do not support the buffer API. So, get the data /* Unicode objects do not support the buffer API. So, get the data
directly instead. */ directly instead. */
...@@ -1686,26 +1685,21 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize) ...@@ -1686,26 +1685,21 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize)
} }
/* get pointer to string buffer */ /* get pointer to string buffer */
view.len = -1; view->len = -1;
buffer = Py_TYPE(string)->tp_as_buffer; buffer = Py_TYPE(string)->tp_as_buffer;
if (!buffer || !buffer->bf_getbuffer || if (!buffer || !buffer->bf_getbuffer ||
(*buffer->bf_getbuffer)(string, &view, PyBUF_SIMPLE) < 0) { (*buffer->bf_getbuffer)(string, view, PyBUF_SIMPLE) < 0) {
PyErr_SetString(PyExc_TypeError, "expected string or buffer"); PyErr_SetString(PyExc_TypeError, "expected string or buffer");
return NULL; return NULL;
} }
/* determine buffer size */ /* determine buffer size */
bytes = view.len; bytes = view->len;
ptr = view.buf; ptr = view->buf;
/* Release the buffer immediately --- possibly dangerous
but doing something else would require some re-factoring
*/
PyBuffer_Release(&view);
if (bytes < 0) { if (bytes < 0) {
PyErr_SetString(PyExc_TypeError, "buffer has negative size"); PyErr_SetString(PyExc_TypeError, "buffer has negative size");
return NULL; goto err;
} }
/* determine character size */ /* determine character size */
...@@ -1719,7 +1713,7 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize) ...@@ -1719,7 +1713,7 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize)
#endif #endif
else { else {
PyErr_SetString(PyExc_TypeError, "buffer size mismatch"); PyErr_SetString(PyExc_TypeError, "buffer size mismatch");
return NULL; goto err;
} }
*p_length = size; *p_length = size;
...@@ -1728,8 +1722,13 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize) ...@@ -1728,8 +1722,13 @@ getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize)
if (ptr == NULL) { if (ptr == NULL) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Buffer is NULL"); "Buffer is NULL");
goto err;
} }
return ptr; return ptr;
err:
PyBuffer_Release(view);
view->buf = NULL;
return NULL;
} }
LOCAL(PyObject*) LOCAL(PyObject*)
...@@ -1747,20 +1746,21 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, ...@@ -1747,20 +1746,21 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string,
state->lastmark = -1; state->lastmark = -1;
state->lastindex = -1; state->lastindex = -1;
ptr = getstring(string, &length, &charsize); state->buffer.buf = NULL;
ptr = getstring(string, &length, &charsize, &state->buffer);
if (!ptr) if (!ptr)
return NULL; goto err;
if (charsize == 1 && pattern->charsize > 1) { if (charsize == 1 && pattern->charsize > 1) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"can't use a string pattern on a bytes-like object"); "can't use a string pattern on a bytes-like object");
return NULL; goto err;
} }
if (charsize > 1 && pattern->charsize == 1) { if (charsize > 1 && pattern->charsize == 1) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"can't use a bytes pattern on a string-like object"); "can't use a bytes pattern on a string-like object");
return NULL; goto err;
} }
/* adjust boundaries */ /* adjust boundaries */
if (start < 0) if (start < 0)
...@@ -1797,11 +1797,17 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, ...@@ -1797,11 +1797,17 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string,
state->lower = sre_lower; state->lower = sre_lower;
return string; return string;
err:
if (state->buffer.buf)
PyBuffer_Release(&state->buffer);
return NULL;
} }
LOCAL(void) LOCAL(void)
state_fini(SRE_STATE* state) state_fini(SRE_STATE* state)
{ {
if (state->buffer.buf)
PyBuffer_Release(&state->buffer);
Py_XDECREF(state->string); Py_XDECREF(state->string);
data_stack_dealloc(state); data_stack_dealloc(state);
} }
...@@ -1863,6 +1869,8 @@ pattern_dealloc(PatternObject* self) ...@@ -1863,6 +1869,8 @@ pattern_dealloc(PatternObject* self)
{ {
if (self->weakreflist != NULL) if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self); PyObject_ClearWeakRefs((PyObject *) self);
if (self->view.buf)
PyBuffer_Release(&self->view);
Py_XDECREF(self->pattern); Py_XDECREF(self->pattern);
Py_XDECREF(self->groupindex); Py_XDECREF(self->groupindex);
Py_XDECREF(self->indexgroup); Py_XDECREF(self->indexgroup);
...@@ -2297,6 +2305,7 @@ pattern_subx(PatternObject* self, PyObject* ptemplate, PyObject* string, ...@@ -2297,6 +2305,7 @@ pattern_subx(PatternObject* self, PyObject* ptemplate, PyObject* string,
Py_ssize_t i, b, e; Py_ssize_t i, b, e;
int bint; int bint;
int filter_is_callable; int filter_is_callable;
Py_buffer view;
if (PyCallable_Check(ptemplate)) { if (PyCallable_Check(ptemplate)) {
/* sub/subn takes either a function or a template */ /* sub/subn takes either a function or a template */
...@@ -2306,7 +2315,8 @@ pattern_subx(PatternObject* self, PyObject* ptemplate, PyObject* string, ...@@ -2306,7 +2315,8 @@ pattern_subx(PatternObject* self, PyObject* ptemplate, PyObject* string,
} else { } else {
/* if not callable, check if it's a literal string */ /* if not callable, check if it's a literal string */
int literal; int literal;
ptr = getstring(ptemplate, &n, &bint); view.buf = NULL;
ptr = getstring(ptemplate, &n, &bint, &view);
b = bint; b = bint;
if (ptr) { if (ptr) {
if (b == 1) { if (b == 1) {
...@@ -2320,6 +2330,8 @@ pattern_subx(PatternObject* self, PyObject* ptemplate, PyObject* string, ...@@ -2320,6 +2330,8 @@ pattern_subx(PatternObject* self, PyObject* ptemplate, PyObject* string,
PyErr_Clear(); PyErr_Clear();
literal = 0; literal = 0;
} }
if (view.buf)
PyBuffer_Release(&view);
if (literal) { if (literal) {
filter = ptemplate; filter = ptemplate;
Py_INCREF(filter); Py_INCREF(filter);
...@@ -2661,6 +2673,7 @@ _compile(PyObject* self_, PyObject* args) ...@@ -2661,6 +2673,7 @@ _compile(PyObject* self_, PyObject* args)
Py_ssize_t groups = 0; Py_ssize_t groups = 0;
PyObject* groupindex = NULL; PyObject* groupindex = NULL;
PyObject* indexgroup = NULL; PyObject* indexgroup = NULL;
if (!PyArg_ParseTuple(args, "OiO!|nOO", &pattern, &flags, if (!PyArg_ParseTuple(args, "OiO!|nOO", &pattern, &flags,
&PyList_Type, &code, &groups, &PyList_Type, &code, &groups,
&groupindex, &indexgroup)) &groupindex, &indexgroup))
...@@ -2675,6 +2688,7 @@ _compile(PyObject* self_, PyObject* args) ...@@ -2675,6 +2688,7 @@ _compile(PyObject* self_, PyObject* args)
self->pattern = NULL; self->pattern = NULL;
self->groupindex = NULL; self->groupindex = NULL;
self->indexgroup = NULL; self->indexgroup = NULL;
self->view.buf = NULL;
self->codesize = n; self->codesize = n;
...@@ -2694,15 +2708,15 @@ _compile(PyObject* self_, PyObject* args) ...@@ -2694,15 +2708,15 @@ _compile(PyObject* self_, PyObject* args)
return NULL; return NULL;
} }
if (pattern == Py_None) if (pattern == Py_None)
self->charsize = -1; self->charsize = -1;
else { else {
Py_ssize_t p_length; Py_ssize_t p_length;
if (!getstring(pattern, &p_length, &self->charsize)) { if (!getstring(pattern, &p_length, &self->charsize, &self->view)) {
Py_DECREF(self); Py_DECREF(self);
return NULL; return NULL;
} }
} }
Py_INCREF(pattern); Py_INCREF(pattern);
self->pattern = pattern; self->pattern = pattern;
......
...@@ -31,6 +31,7 @@ typedef struct { ...@@ -31,6 +31,7 @@ typedef struct {
int flags; /* flags used when compiling pattern source */ int flags; /* flags used when compiling pattern source */
PyObject *weakreflist; /* List of weak references */ PyObject *weakreflist; /* List of weak references */
int charsize; /* pattern charsize (or -1) */ int charsize; /* pattern charsize (or -1) */
Py_buffer view;
/* pattern code */ /* pattern code */
Py_ssize_t codesize; Py_ssize_t codesize;
SRE_CODE code[1]; SRE_CODE code[1];
...@@ -80,6 +81,7 @@ typedef struct { ...@@ -80,6 +81,7 @@ typedef struct {
char* data_stack; char* data_stack;
size_t data_stack_size; size_t data_stack_size;
size_t data_stack_base; size_t data_stack_base;
Py_buffer buffer;
/* current repeat context */ /* current repeat context */
SRE_REPEAT *repeat; SRE_REPEAT *repeat;
/* hooks */ /* hooks */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment