mirror of https://github.com/python/cpython.git
[3.11] gh-103987: fix several crashes in mmap module (GH-103990) (#104677)
gh-103987: fix several crashes in mmap module (GH-103990)
(cherry picked from commit ceaa4c3476
)
Co-authored-by: Prince Roshan <princekrroshan01@gmail.com>
Co-authored-by: sunmy2019 <59365878+sunmy2019@users.noreply.github.com>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
This commit is contained in:
parent
2801b3f8f7
commit
dbb011afae
|
@ -407,7 +407,6 @@ def test_move(self):
|
||||||
m.move(0, 0, 1)
|
m.move(0, 0, 1)
|
||||||
m.move(0, 0, 0)
|
m.move(0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
def test_anonymous(self):
|
def test_anonymous(self):
|
||||||
# anonymous mmap.mmap(-1, PAGE)
|
# anonymous mmap.mmap(-1, PAGE)
|
||||||
m = mmap.mmap(-1, PAGESIZE)
|
m = mmap.mmap(-1, PAGESIZE)
|
||||||
|
@ -887,6 +886,92 @@ def test_resize_succeeds_with_error_for_second_named_mapping(self):
|
||||||
self.assertEqual(m1[:data_length], data)
|
self.assertEqual(m1[:data_length], data)
|
||||||
self.assertEqual(m2[:data_length], data)
|
self.assertEqual(m2[:data_length], data)
|
||||||
|
|
||||||
|
def test_mmap_closed_by_int_scenarios(self):
|
||||||
|
"""
|
||||||
|
gh-103987: Test that mmap objects raise ValueError
|
||||||
|
for closed mmap files
|
||||||
|
"""
|
||||||
|
|
||||||
|
class MmapClosedByIntContext:
|
||||||
|
def __init__(self, access) -> None:
|
||||||
|
self.access = access
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.f = open(TESTFN, "w+b")
|
||||||
|
self.f.write(random.randbytes(100))
|
||||||
|
self.f.flush()
|
||||||
|
|
||||||
|
m = mmap.mmap(self.f.fileno(), 100, access=self.access)
|
||||||
|
|
||||||
|
class X:
|
||||||
|
def __index__(self):
|
||||||
|
m.close()
|
||||||
|
return 10
|
||||||
|
|
||||||
|
return (m, X)
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
self.f.close()
|
||||||
|
|
||||||
|
read_access_modes = [
|
||||||
|
mmap.ACCESS_READ,
|
||||||
|
mmap.ACCESS_WRITE,
|
||||||
|
mmap.ACCESS_COPY,
|
||||||
|
mmap.ACCESS_DEFAULT,
|
||||||
|
]
|
||||||
|
|
||||||
|
write_access_modes = [
|
||||||
|
mmap.ACCESS_WRITE,
|
||||||
|
mmap.ACCESS_COPY,
|
||||||
|
mmap.ACCESS_DEFAULT,
|
||||||
|
]
|
||||||
|
|
||||||
|
for access in read_access_modes:
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m[X()]
|
||||||
|
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m[X() : 20]
|
||||||
|
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m[X() : 20 : 2]
|
||||||
|
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m[20 : X() : -2]
|
||||||
|
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m.read(X())
|
||||||
|
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m.find(b"1", 1, X())
|
||||||
|
|
||||||
|
for access in write_access_modes:
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m[X() : 20] = b"1" * 10
|
||||||
|
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m[X() : 20 : 2] = b"1" * 5
|
||||||
|
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m[20 : X() : -2] = b"1" * 5
|
||||||
|
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m.move(1, 2, X())
|
||||||
|
|
||||||
|
with MmapClosedByIntContext(access) as (m, X):
|
||||||
|
with self.assertRaisesRegex(ValueError, "mmap closed or invalid"):
|
||||||
|
m.write_byte(X())
|
||||||
|
|
||||||
class LargeMmapTests(unittest.TestCase):
|
class LargeMmapTests(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
In :mod:`mmap`, fix several bugs that could lead to access to memory-mapped files after
|
||||||
|
they have been invalidated.
|
|
@ -292,7 +292,8 @@ mmap_read_method(mmap_object *self,
|
||||||
|
|
||||||
CHECK_VALID(NULL);
|
CHECK_VALID(NULL);
|
||||||
if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes))
|
if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes))
|
||||||
return(NULL);
|
return NULL;
|
||||||
|
CHECK_VALID(NULL);
|
||||||
|
|
||||||
/* silently 'adjust' out-of-range requests */
|
/* silently 'adjust' out-of-range requests */
|
||||||
remaining = (self->pos < self->size) ? self->size - self->pos : 0;
|
remaining = (self->pos < self->size) ? self->size - self->pos : 0;
|
||||||
|
@ -333,6 +334,7 @@ mmap_gfind(mmap_object *self,
|
||||||
end = self->size;
|
end = self->size;
|
||||||
|
|
||||||
Py_ssize_t res;
|
Py_ssize_t res;
|
||||||
|
CHECK_VALID(NULL);
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
res = _PyBytes_ReverseFind(
|
res = _PyBytes_ReverseFind(
|
||||||
self->data + start, end - start,
|
self->data + start, end - start,
|
||||||
|
@ -396,7 +398,7 @@ mmap_write_method(mmap_object *self,
|
||||||
|
|
||||||
CHECK_VALID(NULL);
|
CHECK_VALID(NULL);
|
||||||
if (!PyArg_ParseTuple(args, "y*:write", &data))
|
if (!PyArg_ParseTuple(args, "y*:write", &data))
|
||||||
return(NULL);
|
return NULL;
|
||||||
|
|
||||||
if (!is_writable(self)) {
|
if (!is_writable(self)) {
|
||||||
PyBuffer_Release(&data);
|
PyBuffer_Release(&data);
|
||||||
|
@ -409,6 +411,7 @@ mmap_write_method(mmap_object *self,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHECK_VALID(NULL);
|
||||||
memcpy(&self->data[self->pos], data.buf, data.len);
|
memcpy(&self->data[self->pos], data.buf, data.len);
|
||||||
self->pos += data.len;
|
self->pos += data.len;
|
||||||
PyBuffer_Release(&data);
|
PyBuffer_Release(&data);
|
||||||
|
@ -428,6 +431,7 @@ mmap_write_byte_method(mmap_object *self,
|
||||||
if (!is_writable(self))
|
if (!is_writable(self))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
CHECK_VALID(NULL);
|
||||||
if (self->pos < self->size) {
|
if (self->pos < self->size) {
|
||||||
self->data[self->pos++] = value;
|
self->data[self->pos++] = value;
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
@ -732,6 +736,7 @@ mmap_move_method(mmap_object *self, PyObject *args)
|
||||||
if (self->size - dest < cnt || self->size - src < cnt)
|
if (self->size - dest < cnt || self->size - src < cnt)
|
||||||
goto bounds;
|
goto bounds;
|
||||||
|
|
||||||
|
CHECK_VALID(NULL);
|
||||||
memmove(&self->data[dest], &self->data[src], cnt);
|
memmove(&self->data[dest], &self->data[src], cnt);
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
@ -857,6 +862,7 @@ mmap_madvise_method(mmap_object *self, PyObject *args)
|
||||||
length = self->size - start;
|
length = self->size - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHECK_VALID(NULL);
|
||||||
if (madvise(self->data + start, length, option) != 0) {
|
if (madvise(self->data + start, length, option) != 0) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -955,6 +961,7 @@ mmap_subscript(mmap_object *self, PyObject *item)
|
||||||
"mmap index out of range");
|
"mmap index out of range");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
CHECK_VALID(NULL);
|
||||||
return PyLong_FromLong(Py_CHARMASK(self->data[i]));
|
return PyLong_FromLong(Py_CHARMASK(self->data[i]));
|
||||||
}
|
}
|
||||||
else if (PySlice_Check(item)) {
|
else if (PySlice_Check(item)) {
|
||||||
|
@ -965,6 +972,7 @@ mmap_subscript(mmap_object *self, PyObject *item)
|
||||||
}
|
}
|
||||||
slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
|
slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step);
|
||||||
|
|
||||||
|
CHECK_VALID(NULL);
|
||||||
if (slicelen <= 0)
|
if (slicelen <= 0)
|
||||||
return PyBytes_FromStringAndSize("", 0);
|
return PyBytes_FromStringAndSize("", 0);
|
||||||
else if (step == 1)
|
else if (step == 1)
|
||||||
|
@ -978,6 +986,7 @@ mmap_subscript(mmap_object *self, PyObject *item)
|
||||||
|
|
||||||
if (result_buf == NULL)
|
if (result_buf == NULL)
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
|
|
||||||
for (cur = start, i = 0; i < slicelen;
|
for (cur = start, i = 0; i < slicelen;
|
||||||
cur += step, i++) {
|
cur += step, i++) {
|
||||||
result_buf[i] = self->data[cur];
|
result_buf[i] = self->data[cur];
|
||||||
|
@ -1062,6 +1071,7 @@ mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
|
||||||
"in range(0, 256)");
|
"in range(0, 256)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
CHECK_VALID(-1);
|
||||||
self->data[i] = (char) v;
|
self->data[i] = (char) v;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1087,6 +1097,7 @@ mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHECK_VALID(-1);
|
||||||
if (slicelen == 0) {
|
if (slicelen == 0) {
|
||||||
}
|
}
|
||||||
else if (step == 1) {
|
else if (step == 1) {
|
||||||
|
|
Loading…
Reference in New Issue