Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-92888: Fix memoryview bad__index__ use after free#92946

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Fidget-Spinner merged 12 commits intopython:mainfromFidget-Spinner:fix_memoryview_auf
Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
Show all changes
12 commits
Select commitHold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
Address Victor's review
  • Loading branch information
@Fidget-Spinner
Fidget-Spinner committedMay 29, 2022
commit68907139c943d168f19b2a4c116f9a2b055e3180
8 changes: 3 additions & 5 deletionsLib/test/test_memoryview.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -546,6 +546,9 @@ def test_pickle(self):
pickle.dumps(m, proto)

def test_use_released_memory(self):
# gh-92888: Previously it was possible to use a memoryview even after
# backing buffer is freed in certain cases. This tests that those
# cases raise an exception.
size = 128
def release():
m.release()
Expand All@@ -564,25 +567,20 @@ def __bool__(self):
release()
return True

ba = None
m = memoryview(bytearray(b'\xff'*size))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

In my PR, I tried to make the code more generic to test more cases:https://github.com/python/cpython/pull/93127/files#diff-d41c6bb40a1e03fea5a20d15c4077413e0ddde65651147922b625b03a66a2f16R399:

        tp = self.rw_type        b = self.rw_type(self._source)        view = self._view(b)

with self.assertRaises(ValueError):
m[MyIndex()]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This test is very long. Can you try to factorize similar code and use loop with subTest(), and put pack operations in one test method and unpack in another test method?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Then we will need to duplicate the definitions of internal classes.

The tested code is so different, that it is difficult to use a loop. And I think that the result will be more complicated.


ba = None

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

It is necessary. The old bytearray should be deallocated before creating a new bytearray, so all bytearrays will be allocated at the same place.

m = memoryview(bytearray(b'\xff'*size))
self.assertEqual(list(m[:MyIndex()]), [255] * 4)

ba = None
m = memoryview(bytearray(b'\xff'*size))
self.assertEqual(list(m[MyIndex():8]), [255] * 4)

ba = None
m = memoryview(bytearray(b'\xff'*size)).cast('B', (64, 2))
with self.assertRaisesRegex(ValueError, "operation forbidden"):
m[MyIndex(), 0]

ba = None
m = memoryview(bytearray(b'\xff'*size)).cast('B', (2, 64))
with self.assertRaisesRegex(ValueError, "operation forbidden"):
m[0, MyIndex()]
Expand Down
29 changes: 16 additions & 13 deletionsObjects/memoryobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -193,6 +193,11 @@ PyTypeObject _PyManagedBuffer_Type = {
return -1; \
}

/* See gh-92888. These macros signal that we need to check the memoryview
again due to possible read after frees. */
#define CHECK_RELEASED_AGAIN(mv) CHECK_RELEASED(mv)
#define CHECK_RELEASED_INT_AGAIN(mv) CHECK_RELEASED_INT(mv)

#define CHECK_LIST_OR_TUPLE(v) \
if (!PyList_Check(v) && !PyTuple_Check(v)) { \
PyErr_SetString(PyExc_TypeError, \
Expand DownExpand Up@@ -383,7 +388,7 @@ copy_rec(const Py_ssize_t *shape, Py_ssize_t ndim, Py_ssize_t itemsize,
static int
copy_single(PyMemoryViewObject *self, const Py_buffer *dest, const Py_buffer *src)
{
CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_INT_AGAIN(self);
char *mem = NULL;

assert(dest->ndim == 1);
Expand DownExpand Up@@ -1690,7 +1695,7 @@ unpack_single(PyMemoryViewObject *self, const char *ptr, const char *fmt)
unsigned char uc;
void *p;

CHECK_RELEASED(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_AGAIN(self);

switch (fmt[0]) {

Expand DownExpand Up@@ -1781,15 +1786,13 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt
double d;
void *p;

CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */

switch (fmt[0]) {
/* signed integers */
case 'b': case 'h': case 'i': case 'l':
ld = pylong_as_ld(item);
if (ld == -1 && PyErr_Occurred())
goto err_occurred;
CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_INT_AGAIN(self);
switch (fmt[0]) {
case 'b':
if (ld < SCHAR_MIN || ld > SCHAR_MAX) goto err_range;
Expand All@@ -1810,7 +1813,7 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt
lu = pylong_as_lu(item);
if (lu == (unsigned long)-1 && PyErr_Occurred())
goto err_occurred;
CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_INT_AGAIN(self);
switch (fmt[0]) {
case 'B':
if (lu > UCHAR_MAX) goto err_range;
Expand All@@ -1831,14 +1834,14 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt
lld = pylong_as_lld(item);
if (lld == -1 && PyErr_Occurred())
goto err_occurred;
CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_INT_AGAIN(self);
PACK_SINGLE(ptr, lld, long long);
break;
case 'Q':
llu = pylong_as_llu(item);
if (llu == (unsigned long long)-1 && PyErr_Occurred())
goto err_occurred;
CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_INT_AGAIN(self);
PACK_SINGLE(ptr, llu, unsigned long long);
break;

Expand All@@ -1847,14 +1850,14 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt
zd = pylong_as_zd(item);
if (zd == -1 && PyErr_Occurred())
goto err_occurred;
CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_INT_AGAIN(self);
PACK_SINGLE(ptr, zd, Py_ssize_t);
break;
case 'N':
zu = pylong_as_zu(item);
if (zu == (size_t)-1 && PyErr_Occurred())
goto err_occurred;
CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_INT_AGAIN(self);
PACK_SINGLE(ptr, zu, size_t);
break;

Expand All@@ -1863,7 +1866,7 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt
d = PyFloat_AsDouble(item);
if (d == -1.0 && PyErr_Occurred())
goto err_occurred;
CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_INT_AGAIN(self);
if (fmt[0] == 'f') {
PACK_SINGLE(ptr, d, float);
}
Expand All@@ -1877,7 +1880,7 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt
ld = PyObject_IsTrue(item);
if (ld < 0)
return -1; /* preserve original error */
CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_INT_AGAIN(self);
PACK_SINGLE(ptr, ld, _Bool);
break;

Expand All@@ -1895,7 +1898,7 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt
p = PyLong_AsVoidPtr(item);
if (p == NULL && PyErr_Occurred())
goto err_occurred;
CHECK_RELEASED_INT(self); /* See gh-92888 for why we need this here */
CHECK_RELEASED_INT_AGAIN(self);
PACK_SINGLE(ptr, p, void *);
break;

Expand Down

[8]ページ先頭

©2009-2026 Movatter.jp