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

Commit2eff55c

Browse files
gh-92888: Fix memoryview bad__index__ use after free (GH-92946)
Co-authored-by: chilaxan <35645806+chilaxan@users.noreply.github.com>Co-authored-by: Serhiy Storchaka <3659035+serhiy-storchaka@users.noreply.github.com>(cherry picked from commit11190c4)Co-authored-by: Ken Jin <kenjin@python.org>
1 parent6c8eb95 commit2eff55c

File tree

3 files changed

+139
-19
lines changed

3 files changed

+139
-19
lines changed

‎Lib/test/test_memoryview.py‎

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,107 @@ def test_pickle(self):
545545
withself.assertRaises(TypeError):
546546
pickle.dumps(m,proto)
547547

548+
deftest_use_released_memory(self):
549+
# gh-92888: Previously it was possible to use a memoryview even after
550+
# backing buffer is freed in certain cases. This tests that those
551+
# cases raise an exception.
552+
size=128
553+
defrelease():
554+
m.release()
555+
nonlocalba
556+
ba=bytearray(size)
557+
classMyIndex:
558+
def__index__(self):
559+
release()
560+
return4
561+
classMyFloat:
562+
def__float__(self):
563+
release()
564+
return4.25
565+
classMyBool:
566+
def__bool__(self):
567+
release()
568+
returnTrue
569+
570+
ba=None
571+
m=memoryview(bytearray(b'\xff'*size))
572+
withself.assertRaises(ValueError):
573+
m[MyIndex()]
574+
575+
ba=None
576+
m=memoryview(bytearray(b'\xff'*size))
577+
self.assertEqual(list(m[:MyIndex()]), [255]*4)
578+
579+
ba=None
580+
m=memoryview(bytearray(b'\xff'*size))
581+
self.assertEqual(list(m[MyIndex():8]), [255]*4)
582+
583+
ba=None
584+
m=memoryview(bytearray(b'\xff'*size)).cast('B', (64,2))
585+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
586+
m[MyIndex(),0]
587+
588+
ba=None
589+
m=memoryview(bytearray(b'\xff'*size)).cast('B', (2,64))
590+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
591+
m[0,MyIndex()]
592+
593+
ba=None
594+
m=memoryview(bytearray(b'\xff'*size))
595+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
596+
m[MyIndex()]=42
597+
self.assertEqual(ba[:8],b'\0'*8)
598+
599+
ba=None
600+
m=memoryview(bytearray(b'\xff'*size))
601+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
602+
m[:MyIndex()]=b'spam'
603+
self.assertEqual(ba[:8],b'\0'*8)
604+
605+
ba=None
606+
m=memoryview(bytearray(b'\xff'*size))
607+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
608+
m[MyIndex():8]=b'spam'
609+
self.assertEqual(ba[:8],b'\0'*8)
610+
611+
ba=None
612+
m=memoryview(bytearray(b'\xff'*size)).cast('B', (64,2))
613+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
614+
m[MyIndex(),0]=42
615+
self.assertEqual(ba[8:16],b'\0'*8)
616+
ba=None
617+
m=memoryview(bytearray(b'\xff'*size)).cast('B', (2,64))
618+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
619+
m[0,MyIndex()]=42
620+
self.assertEqual(ba[:8],b'\0'*8)
621+
622+
ba=None
623+
m=memoryview(bytearray(b'\xff'*size))
624+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
625+
m[0]=MyIndex()
626+
self.assertEqual(ba[:8],b'\0'*8)
627+
628+
forfmtin'bhilqnBHILQN':
629+
withself.subTest(fmt=fmt):
630+
ba=None
631+
m=memoryview(bytearray(b'\xff'*size)).cast(fmt)
632+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
633+
m[0]=MyIndex()
634+
self.assertEqual(ba[:8],b'\0'*8)
635+
636+
forfmtin'fd':
637+
withself.subTest(fmt=fmt):
638+
ba=None
639+
m=memoryview(bytearray(b'\xff'*size)).cast(fmt)
640+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
641+
m[0]=MyFloat()
642+
self.assertEqual(ba[:8],b'\0'*8)
643+
644+
ba=None
645+
m=memoryview(bytearray(b'\xff'*size)).cast('?')
646+
withself.assertRaisesRegex(ValueError,"operation forbidden"):
647+
m[0]=MyBool()
648+
self.assertEqual(ba[:8],b'\0'*8)
548649

549650
if__name__=="__main__":
550651
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix ``memoryview`` use after free when accessing the backing buffer in certain cases.
2+

‎Objects/memoryobject.c‎

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ PyTypeObject _PyManagedBuffer_Type = {
193193
return -1; \
194194
}
195195

196+
/* See gh-92888. These macros signal that we need to check the memoryview
197+
again due to possible read after frees. */
198+
#defineCHECK_RELEASED_AGAIN(mv) CHECK_RELEASED(mv)
199+
#defineCHECK_RELEASED_INT_AGAIN(mv) CHECK_RELEASED_INT(mv)
200+
196201
#defineCHECK_LIST_OR_TUPLE(v) \
197202
if (!PyList_Check(v) && !PyTuple_Check(v)) { \
198203
PyErr_SetString(PyExc_TypeError, \
@@ -381,8 +386,9 @@ copy_rec(const Py_ssize_t *shape, Py_ssize_t ndim, Py_ssize_t itemsize,
381386

382387
/* Faster copying of one-dimensional arrays. */
383388
staticint
384-
copy_single(constPy_buffer*dest,constPy_buffer*src)
389+
copy_single(PyMemoryViewObject*self,constPy_buffer*dest,constPy_buffer*src)
385390
{
391+
CHECK_RELEASED_INT_AGAIN(self);
386392
char*mem=NULL;
387393

388394
assert(dest->ndim==1);
@@ -1677,7 +1683,7 @@ pylong_as_zu(PyObject *item)
16771683
module syntax. This function is very sensitive to small changes. With this
16781684
layout gcc automatically generates a fast jump table. */
16791685
staticinlinePyObject*
1680-
unpack_single(constchar*ptr,constchar*fmt)
1686+
unpack_single(PyMemoryViewObject*self,constchar*ptr,constchar*fmt)
16811687
{
16821688
unsigned long longllu;
16831689
unsigned longlu;
@@ -1689,6 +1695,8 @@ unpack_single(const char *ptr, const char *fmt)
16891695
unsignedcharuc;
16901696
void*p;
16911697

1698+
CHECK_RELEASED_AGAIN(self);
1699+
16921700
switch (fmt[0]) {
16931701

16941702
/* signed integers and fast path for 'B' */
@@ -1767,7 +1775,7 @@ unpack_single(const char *ptr, const char *fmt)
17671775
/* Pack a single item. 'fmt' can be any native format character in
17681776
struct module syntax. */
17691777
staticint
1770-
pack_single(char*ptr,PyObject*item,constchar*fmt)
1778+
pack_single(PyMemoryViewObject*self,char*ptr,PyObject*item,constchar*fmt)
17711779
{
17721780
unsigned long longllu;
17731781
unsigned longlu;
@@ -1784,6 +1792,7 @@ pack_single(char *ptr, PyObject *item, const char *fmt)
17841792
ld=pylong_as_ld(item);
17851793
if (ld==-1&&PyErr_Occurred())
17861794
gotoerr_occurred;
1795+
CHECK_RELEASED_INT_AGAIN(self);
17871796
switch (fmt[0]) {
17881797
case'b':
17891798
if (ld<SCHAR_MIN||ld>SCHAR_MAX) gotoerr_range;
@@ -1804,6 +1813,7 @@ pack_single(char *ptr, PyObject *item, const char *fmt)
18041813
lu=pylong_as_lu(item);
18051814
if (lu== (unsigned long)-1&&PyErr_Occurred())
18061815
gotoerr_occurred;
1816+
CHECK_RELEASED_INT_AGAIN(self);
18071817
switch (fmt[0]) {
18081818
case'B':
18091819
if (lu>UCHAR_MAX) gotoerr_range;
@@ -1824,12 +1834,14 @@ pack_single(char *ptr, PyObject *item, const char *fmt)
18241834
lld=pylong_as_lld(item);
18251835
if (lld==-1&&PyErr_Occurred())
18261836
gotoerr_occurred;
1837+
CHECK_RELEASED_INT_AGAIN(self);
18271838
PACK_SINGLE(ptr,lld,longlong);
18281839
break;
18291840
case'Q':
18301841
llu=pylong_as_llu(item);
18311842
if (llu== (unsigned long long)-1&&PyErr_Occurred())
18321843
gotoerr_occurred;
1844+
CHECK_RELEASED_INT_AGAIN(self);
18331845
PACK_SINGLE(ptr,llu,unsignedlong long);
18341846
break;
18351847

@@ -1838,12 +1850,14 @@ pack_single(char *ptr, PyObject *item, const char *fmt)
18381850
zd=pylong_as_zd(item);
18391851
if (zd==-1&&PyErr_Occurred())
18401852
gotoerr_occurred;
1853+
CHECK_RELEASED_INT_AGAIN(self);
18411854
PACK_SINGLE(ptr,zd,Py_ssize_t);
18421855
break;
18431856
case'N':
18441857
zu=pylong_as_zu(item);
18451858
if (zu== (size_t)-1&&PyErr_Occurred())
18461859
gotoerr_occurred;
1860+
CHECK_RELEASED_INT_AGAIN(self);
18471861
PACK_SINGLE(ptr,zu,size_t);
18481862
break;
18491863

@@ -1852,6 +1866,7 @@ pack_single(char *ptr, PyObject *item, const char *fmt)
18521866
d=PyFloat_AsDouble(item);
18531867
if (d==-1.0&&PyErr_Occurred())
18541868
gotoerr_occurred;
1869+
CHECK_RELEASED_INT_AGAIN(self);
18551870
if (fmt[0]=='f') {
18561871
PACK_SINGLE(ptr,d,float);
18571872
}
@@ -1865,6 +1880,7 @@ pack_single(char *ptr, PyObject *item, const char *fmt)
18651880
ld=PyObject_IsTrue(item);
18661881
if (ld<0)
18671882
return-1;/* preserve original error */
1883+
CHECK_RELEASED_INT_AGAIN(self);
18681884
PACK_SINGLE(ptr,ld,_Bool);
18691885
break;
18701886

@@ -1882,6 +1898,7 @@ pack_single(char *ptr, PyObject *item, const char *fmt)
18821898
p=PyLong_AsVoidPtr(item);
18831899
if (p==NULL&&PyErr_Occurred())
18841900
gotoerr_occurred;
1901+
CHECK_RELEASED_INT_AGAIN(self);
18851902
PACK_SINGLE(ptr,p,void*);
18861903
break;
18871904

@@ -2048,7 +2065,7 @@ adjust_fmt(const Py_buffer *view)
20482065

20492066
/* Base case for multi-dimensional unpacking. Assumption: ndim == 1. */
20502067
staticPyObject*
2051-
tolist_base(constchar*ptr,constPy_ssize_t*shape,
2068+
tolist_base(PyMemoryViewObject*self,constchar*ptr,constPy_ssize_t*shape,
20522069
constPy_ssize_t*strides,constPy_ssize_t*suboffsets,
20532070
constchar*fmt)
20542071
{
@@ -2061,7 +2078,7 @@ tolist_base(const char *ptr, const Py_ssize_t *shape,
20612078

20622079
for (i=0;i<shape[0];ptr+=strides[0],i++) {
20632080
constchar*xptr=ADJUST_PTR(ptr,suboffsets,0);
2064-
item=unpack_single(xptr,fmt);
2081+
item=unpack_single(self,xptr,fmt);
20652082
if (item==NULL) {
20662083
Py_DECREF(lst);
20672084
returnNULL;
@@ -2075,7 +2092,7 @@ tolist_base(const char *ptr, const Py_ssize_t *shape,
20752092
/* Unpack a multi-dimensional array into a nested list.
20762093
Assumption: ndim >= 1. */
20772094
staticPyObject*
2078-
tolist_rec(constchar*ptr,Py_ssize_tndim,constPy_ssize_t*shape,
2095+
tolist_rec(PyMemoryViewObject*self,constchar*ptr,Py_ssize_tndim,constPy_ssize_t*shape,
20792096
constPy_ssize_t*strides,constPy_ssize_t*suboffsets,
20802097
constchar*fmt)
20812098
{
@@ -2087,15 +2104,15 @@ tolist_rec(const char *ptr, Py_ssize_t ndim, const Py_ssize_t *shape,
20872104
assert(strides!=NULL);
20882105

20892106
if (ndim==1)
2090-
returntolist_base(ptr,shape,strides,suboffsets,fmt);
2107+
returntolist_base(self,ptr,shape,strides,suboffsets,fmt);
20912108

20922109
lst=PyList_New(shape[0]);
20932110
if (lst==NULL)
20942111
returnNULL;
20952112

20962113
for (i=0;i<shape[0];ptr+=strides[0],i++) {
20972114
constchar*xptr=ADJUST_PTR(ptr,suboffsets,0);
2098-
item=tolist_rec(xptr,ndim-1,shape+1,
2115+
item=tolist_rec(self,xptr,ndim-1,shape+1,
20992116
strides+1,suboffsets ?suboffsets+1 :NULL,
21002117
fmt);
21012118
if (item==NULL) {
@@ -2129,15 +2146,15 @@ memoryview_tolist_impl(PyMemoryViewObject *self)
21292146
if (fmt==NULL)
21302147
returnNULL;
21312148
if (view->ndim==0) {
2132-
returnunpack_single(view->buf,fmt);
2149+
returnunpack_single(self,view->buf,fmt);
21332150
}
21342151
elseif (view->ndim==1) {
2135-
returntolist_base(view->buf,view->shape,
2152+
returntolist_base(self,view->buf,view->shape,
21362153
view->strides,view->suboffsets,
21372154
fmt);
21382155
}
21392156
else {
2140-
returntolist_rec(view->buf,view->ndim,view->shape,
2157+
returntolist_rec(self,view->buf,view->ndim,view->shape,
21412158
view->strides,view->suboffsets,
21422159
fmt);
21432160
}
@@ -2345,7 +2362,7 @@ memory_item(PyMemoryViewObject *self, Py_ssize_t index)
23452362
char*ptr=ptr_from_index(view,index);
23462363
if (ptr==NULL)
23472364
returnNULL;
2348-
returnunpack_single(ptr,fmt);
2365+
returnunpack_single(self,ptr,fmt);
23492366
}
23502367

23512368
PyErr_SetString(PyExc_NotImplementedError,
@@ -2376,7 +2393,7 @@ memory_item_multi(PyMemoryViewObject *self, PyObject *tup)
23762393
ptr=ptr_from_tuple(view,tup);
23772394
if (ptr==NULL)
23782395
returnNULL;
2379-
returnunpack_single(ptr,fmt);
2396+
returnunpack_single(self,ptr,fmt);
23802397
}
23812398

23822399
staticinlineint
@@ -2463,7 +2480,7 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key)
24632480
constchar*fmt=adjust_fmt(view);
24642481
if (fmt==NULL)
24652482
returnNULL;
2466-
returnunpack_single(view->buf,fmt);
2483+
returnunpack_single(self,view->buf,fmt);
24672484
}
24682485
elseif (key==Py_Ellipsis) {
24692486
Py_INCREF(self);
@@ -2538,7 +2555,7 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
25382555
if (key==Py_Ellipsis||
25392556
(PyTuple_Check(key)&&PyTuple_GET_SIZE(key)==0)) {
25402557
ptr= (char*)view->buf;
2541-
returnpack_single(ptr,value,fmt);
2558+
returnpack_single(self,ptr,value,fmt);
25422559
}
25432560
else {
25442561
PyErr_SetString(PyExc_TypeError,
@@ -2560,7 +2577,7 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
25602577
ptr=ptr_from_index(view,index);
25612578
if (ptr==NULL)
25622579
return-1;
2563-
returnpack_single(ptr,value,fmt);
2580+
returnpack_single(self,ptr,value,fmt);
25642581
}
25652582
/* one-dimensional: fast path */
25662583
if (PySlice_Check(key)&&view->ndim==1) {
@@ -2583,7 +2600,7 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
25832600
gotoend_block;
25842601
dest.len=dest.shape[0]*dest.itemsize;
25852602

2586-
ret=copy_single(&dest,&src);
2603+
ret=copy_single(self,&dest,&src);
25872604

25882605
end_block:
25892606
PyBuffer_Release(&src);
@@ -2599,7 +2616,7 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
25992616
ptr=ptr_from_tuple(view,key);
26002617
if (ptr==NULL)
26012618
return-1;
2602-
returnpack_single(ptr,value,fmt);
2619+
returnpack_single(self,ptr,value,fmt);
26032620
}
26042621
if (PySlice_Check(key)||is_multislice(key)) {
26052622
/* Call memory_subscript() to produce a sliced lvalue, then copy
@@ -3200,7 +3217,7 @@ memoryiter_next(memoryiterobject *it)
32003217
if (ptr==NULL) {
32013218
returnNULL;
32023219
}
3203-
returnunpack_single(ptr,it->it_fmt);
3220+
returnunpack_single(seq,ptr,it->it_fmt);
32043221
}
32053222

32063223
it->it_seq=NULL;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp