mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	gh-112087: Make __sizeof__ and listiter_{len, next} to be threadsafe (gh-114843)
This commit is contained in:
		
							parent
							
								
									4b2d1786cc
								
							
						
					
					
						commit
						a2d4281415
					
				
					 7 changed files with 80 additions and 69 deletions
				
			
		| 
						 | 
					@ -1727,6 +1727,8 @@ def _check_tracemalloc():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def check_free_after_iterating(test, iter, cls, args=()):
 | 
					def check_free_after_iterating(test, iter, cls, args=()):
 | 
				
			||||||
 | 
					    done = False
 | 
				
			||||||
 | 
					    def wrapper():
 | 
				
			||||||
        class A(cls):
 | 
					        class A(cls):
 | 
				
			||||||
            def __del__(self):
 | 
					            def __del__(self):
 | 
				
			||||||
                nonlocal done
 | 
					                nonlocal done
 | 
				
			||||||
| 
						 | 
					@ -1736,10 +1738,11 @@ def __del__(self):
 | 
				
			||||||
                except StopIteration:
 | 
					                except StopIteration:
 | 
				
			||||||
                    pass
 | 
					                    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    done = False
 | 
					 | 
				
			||||||
        it = iter(A(*args))
 | 
					        it = iter(A(*args))
 | 
				
			||||||
        # Issue 26494: Shouldn't crash
 | 
					        # Issue 26494: Shouldn't crash
 | 
				
			||||||
        test.assertRaises(StopIteration, next, it)
 | 
					        test.assertRaises(StopIteration, next, it)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wrapper()
 | 
				
			||||||
    # The sequence should be deallocated just after the end of iterating
 | 
					    # The sequence should be deallocated just after the end of iterating
 | 
				
			||||||
    gc_collect()
 | 
					    gc_collect()
 | 
				
			||||||
    test.assertTrue(done)
 | 
					    test.assertTrue(done)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -302,7 +302,7 @@ def __eq__(self, other):
 | 
				
			||||||
            # listiter_reduce_general
 | 
					            # listiter_reduce_general
 | 
				
			||||||
            self.assertEqual(
 | 
					            self.assertEqual(
 | 
				
			||||||
                run("reversed", orig["reversed"](list(range(8)))),
 | 
					                run("reversed", orig["reversed"](list(range(8)))),
 | 
				
			||||||
                (iter, ([],))
 | 
					                (reversed, ([],))
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for case in types:
 | 
					            for case in types:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,2 @@
 | 
				
			||||||
 | 
					For an empty reverse iterator for list will be reduced to :func:`reversed`.
 | 
				
			||||||
 | 
					Patch by Donghee Na
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,14 @@ class list "PyListObject *" "&PyList_Type"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_Py_DECLARE_STR(list_err, "list index out of range");
 | 
					_Py_DECLARE_STR(list_err, "list index out of range");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef Py_GIL_DISABLED
 | 
				
			||||||
 | 
					#  define LOAD_SSIZE(value) _Py_atomic_load_ssize_relaxed(&value)
 | 
				
			||||||
 | 
					#  define STORE_SSIZE(value, new_value) _Py_atomic_store_ssize_relaxed(&value, new_value)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#  define LOAD_SSIZE(value) value
 | 
				
			||||||
 | 
					#  define STORE_SSIZE(value, new_value) value = new_value
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef WITH_FREELISTS
 | 
					#ifdef WITH_FREELISTS
 | 
				
			||||||
static struct _Py_list_freelist *
 | 
					static struct _Py_list_freelist *
 | 
				
			||||||
get_list_freelist(void)
 | 
					get_list_freelist(void)
 | 
				
			||||||
| 
						 | 
					@ -2971,7 +2979,8 @@ list___sizeof___impl(PyListObject *self)
 | 
				
			||||||
/*[clinic end generated code: output=3417541f95f9a53e input=b8030a5d5ce8a187]*/
 | 
					/*[clinic end generated code: output=3417541f95f9a53e input=b8030a5d5ce8a187]*/
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    size_t res = _PyObject_SIZE(Py_TYPE(self));
 | 
					    size_t res = _PyObject_SIZE(Py_TYPE(self));
 | 
				
			||||||
    res += (size_t)self->allocated * sizeof(void*);
 | 
					    Py_ssize_t allocated = LOAD_SSIZE(self->allocated);
 | 
				
			||||||
 | 
					    res += (size_t)allocated * sizeof(void*);
 | 
				
			||||||
    return PyLong_FromSize_t(res);
 | 
					    return PyLong_FromSize_t(res);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3373,33 +3382,34 @@ static PyObject *
 | 
				
			||||||
listiter_next(PyObject *self)
 | 
					listiter_next(PyObject *self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    _PyListIterObject *it = (_PyListIterObject *)self;
 | 
					    _PyListIterObject *it = (_PyListIterObject *)self;
 | 
				
			||||||
    PyListObject *seq;
 | 
					    Py_ssize_t index = LOAD_SSIZE(it->it_index);
 | 
				
			||||||
    PyObject *item;
 | 
					    if (index < 0) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert(it != NULL);
 | 
					 | 
				
			||||||
    seq = it->it_seq;
 | 
					 | 
				
			||||||
    if (seq == NULL)
 | 
					 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    assert(PyList_Check(seq));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (it->it_index < PyList_GET_SIZE(seq)) {
 | 
					 | 
				
			||||||
        item = PyList_GET_ITEM(seq, it->it_index);
 | 
					 | 
				
			||||||
        ++it->it_index;
 | 
					 | 
				
			||||||
        return Py_NewRef(item);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PyObject *item = list_get_item_ref(it->it_seq, index);
 | 
				
			||||||
 | 
					    if (item == NULL) {
 | 
				
			||||||
 | 
					        // out-of-bounds
 | 
				
			||||||
 | 
					        STORE_SSIZE(it->it_index, -1);
 | 
				
			||||||
 | 
					#ifndef Py_GIL_DISABLED
 | 
				
			||||||
 | 
					        PyListObject *seq = it->it_seq;
 | 
				
			||||||
        it->it_seq = NULL;
 | 
					        it->it_seq = NULL;
 | 
				
			||||||
        Py_DECREF(seq);
 | 
					        Py_DECREF(seq);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    STORE_SSIZE(it->it_index, index + 1);
 | 
				
			||||||
 | 
					    return item;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyObject *
 | 
					static PyObject *
 | 
				
			||||||
listiter_len(PyObject *self, PyObject *Py_UNUSED(ignored))
 | 
					listiter_len(PyObject *self, PyObject *Py_UNUSED(ignored))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    assert(self != NULL);
 | 
				
			||||||
    _PyListIterObject *it = (_PyListIterObject *)self;
 | 
					    _PyListIterObject *it = (_PyListIterObject *)self;
 | 
				
			||||||
    Py_ssize_t len;
 | 
					    Py_ssize_t index = LOAD_SSIZE(it->it_index);
 | 
				
			||||||
    if (it->it_seq) {
 | 
					    if (index >= 0) {
 | 
				
			||||||
        len = PyList_GET_SIZE(it->it_seq) - it->it_index;
 | 
					        Py_ssize_t len = PyList_GET_SIZE(it->it_seq) - index;
 | 
				
			||||||
        if (len >= 0)
 | 
					        if (len >= 0)
 | 
				
			||||||
            return PyLong_FromSsize_t(len);
 | 
					            return PyLong_FromSsize_t(len);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -3420,8 +3430,8 @@ listiter_setstate(PyObject *self, PyObject *state)
 | 
				
			||||||
    if (index == -1 && PyErr_Occurred())
 | 
					    if (index == -1 && PyErr_Occurred())
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    if (it->it_seq != NULL) {
 | 
					    if (it->it_seq != NULL) {
 | 
				
			||||||
        if (index < 0)
 | 
					        if (index < -1)
 | 
				
			||||||
            index = 0;
 | 
					            index = -1;
 | 
				
			||||||
        else if (index > PyList_GET_SIZE(it->it_seq))
 | 
					        else if (index > PyList_GET_SIZE(it->it_seq))
 | 
				
			||||||
            index = PyList_GET_SIZE(it->it_seq); /* iterator exhausted */
 | 
					            index = PyList_GET_SIZE(it->it_seq); /* iterator exhausted */
 | 
				
			||||||
        it->it_index = index;
 | 
					        it->it_index = index;
 | 
				
			||||||
| 
						 | 
					@ -3526,26 +3536,24 @@ static PyObject *
 | 
				
			||||||
listreviter_next(PyObject *self)
 | 
					listreviter_next(PyObject *self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    listreviterobject *it = (listreviterobject *)self;
 | 
					    listreviterobject *it = (listreviterobject *)self;
 | 
				
			||||||
    PyObject *item;
 | 
					 | 
				
			||||||
    Py_ssize_t index;
 | 
					 | 
				
			||||||
    PyListObject *seq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert(it != NULL);
 | 
					    assert(it != NULL);
 | 
				
			||||||
    seq = it->it_seq;
 | 
					    PyListObject *seq = it->it_seq;
 | 
				
			||||||
    if (seq == NULL) {
 | 
					 | 
				
			||||||
        return NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    assert(PyList_Check(seq));
 | 
					    assert(PyList_Check(seq));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    index = it->it_index;
 | 
					    Py_ssize_t index = LOAD_SSIZE(it->it_index);
 | 
				
			||||||
    if (index>=0 && index < PyList_GET_SIZE(seq)) {
 | 
					    if (index < 0) {
 | 
				
			||||||
        item = PyList_GET_ITEM(seq, index);
 | 
					        return NULL;
 | 
				
			||||||
        it->it_index--;
 | 
					 | 
				
			||||||
        return Py_NewRef(item);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    it->it_index = -1;
 | 
					    PyObject *item = list_get_item_ref(seq, index);
 | 
				
			||||||
 | 
					    if (item != NULL) {
 | 
				
			||||||
 | 
					        STORE_SSIZE(it->it_index, index - 1);
 | 
				
			||||||
 | 
					        return item;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    STORE_SSIZE(it->it_index, -1);
 | 
				
			||||||
 | 
					#ifndef Py_GIL_DISABLED
 | 
				
			||||||
    it->it_seq = NULL;
 | 
					    it->it_seq = NULL;
 | 
				
			||||||
    Py_DECREF(seq);
 | 
					    Py_DECREF(seq);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3553,7 +3561,8 @@ static PyObject *
 | 
				
			||||||
listreviter_len(PyObject *self, PyObject *Py_UNUSED(ignored))
 | 
					listreviter_len(PyObject *self, PyObject *Py_UNUSED(ignored))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    listreviterobject *it = (listreviterobject *)self;
 | 
					    listreviterobject *it = (listreviterobject *)self;
 | 
				
			||||||
    Py_ssize_t len = it->it_index + 1;
 | 
					    Py_ssize_t index = LOAD_SSIZE(it->it_index);
 | 
				
			||||||
 | 
					    Py_ssize_t len = index + 1;
 | 
				
			||||||
    if (it->it_seq == NULL || PyList_GET_SIZE(it->it_seq) < len)
 | 
					    if (it->it_seq == NULL || PyList_GET_SIZE(it->it_seq) < len)
 | 
				
			||||||
        len = 0;
 | 
					        len = 0;
 | 
				
			||||||
    return PyLong_FromSsize_t(len);
 | 
					    return PyLong_FromSsize_t(len);
 | 
				
			||||||
| 
						 | 
					@ -3588,6 +3597,7 @@ static PyObject *
 | 
				
			||||||
listiter_reduce_general(void *_it, int forward)
 | 
					listiter_reduce_general(void *_it, int forward)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PyObject *list;
 | 
					    PyObject *list;
 | 
				
			||||||
 | 
					    PyObject *iter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* _PyEval_GetBuiltin can invoke arbitrary code,
 | 
					    /* _PyEval_GetBuiltin can invoke arbitrary code,
 | 
				
			||||||
     * call must be before access of iterator pointers.
 | 
					     * call must be before access of iterator pointers.
 | 
				
			||||||
| 
						 | 
					@ -3595,29 +3605,21 @@ listiter_reduce_general(void *_it, int forward)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* the objects are not the same, index is of different types! */
 | 
					    /* the objects are not the same, index is of different types! */
 | 
				
			||||||
    if (forward) {
 | 
					    if (forward) {
 | 
				
			||||||
        PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter));
 | 
					        iter = _PyEval_GetBuiltin(&_Py_ID(iter));
 | 
				
			||||||
        if (!iter) {
 | 
					 | 
				
			||||||
            return NULL;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        _PyListIterObject *it = (_PyListIterObject *)_it;
 | 
					        _PyListIterObject *it = (_PyListIterObject *)_it;
 | 
				
			||||||
        if (it->it_seq) {
 | 
					        if (it->it_index >= 0) {
 | 
				
			||||||
            return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index);
 | 
					            return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Py_DECREF(iter);
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        PyObject *reversed = _PyEval_GetBuiltin(&_Py_ID(reversed));
 | 
					        iter = _PyEval_GetBuiltin(&_Py_ID(reversed));
 | 
				
			||||||
        if (!reversed) {
 | 
					 | 
				
			||||||
            return NULL;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        listreviterobject *it = (listreviterobject *)_it;
 | 
					        listreviterobject *it = (listreviterobject *)_it;
 | 
				
			||||||
        if (it->it_seq) {
 | 
					        if (it->it_index >= 0) {
 | 
				
			||||||
            return Py_BuildValue("N(O)n", reversed, it->it_seq, it->it_index);
 | 
					            return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Py_DECREF(reversed);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /* empty iterator, create an empty list */
 | 
					    /* empty iterator, create an empty list */
 | 
				
			||||||
    list = PyList_New(0);
 | 
					    list = PyList_New(0);
 | 
				
			||||||
    if (list == NULL)
 | 
					    if (list == NULL)
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(iter)), list);
 | 
					    return Py_BuildValue("N(N)", iter, list);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2606,11 +2606,14 @@ dummy_func(
 | 
				
			||||||
            assert(Py_TYPE(iter) == &PyListIter_Type);
 | 
					            assert(Py_TYPE(iter) == &PyListIter_Type);
 | 
				
			||||||
            STAT_INC(FOR_ITER, hit);
 | 
					            STAT_INC(FOR_ITER, hit);
 | 
				
			||||||
            PyListObject *seq = it->it_seq;
 | 
					            PyListObject *seq = it->it_seq;
 | 
				
			||||||
            if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) {
 | 
					            if ((size_t)it->it_index >= (size_t)PyList_GET_SIZE(seq)) {
 | 
				
			||||||
 | 
					                it->it_index = -1;
 | 
				
			||||||
 | 
					                #ifndef Py_GIL_DISABLED
 | 
				
			||||||
                if (seq != NULL) {
 | 
					                if (seq != NULL) {
 | 
				
			||||||
                    it->it_seq = NULL;
 | 
					                    it->it_seq = NULL;
 | 
				
			||||||
                    Py_DECREF(seq);
 | 
					                    Py_DECREF(seq);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                #endif
 | 
				
			||||||
                Py_DECREF(iter);
 | 
					                Py_DECREF(iter);
 | 
				
			||||||
                STACK_SHRINK(1);
 | 
					                STACK_SHRINK(1);
 | 
				
			||||||
                /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */
 | 
					                /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */
 | 
				
			||||||
| 
						 | 
					@ -2624,8 +2627,7 @@ dummy_func(
 | 
				
			||||||
            _PyListIterObject *it = (_PyListIterObject *)iter;
 | 
					            _PyListIterObject *it = (_PyListIterObject *)iter;
 | 
				
			||||||
            assert(Py_TYPE(iter) == &PyListIter_Type);
 | 
					            assert(Py_TYPE(iter) == &PyListIter_Type);
 | 
				
			||||||
            PyListObject *seq = it->it_seq;
 | 
					            PyListObject *seq = it->it_seq;
 | 
				
			||||||
            DEOPT_IF(seq == NULL);
 | 
					            DEOPT_IF((size_t)it->it_index >= (size_t)PyList_GET_SIZE(seq));
 | 
				
			||||||
            DEOPT_IF(it->it_index >= PyList_GET_SIZE(seq));
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        op(_ITER_NEXT_LIST, (iter -- iter, next)) {
 | 
					        op(_ITER_NEXT_LIST, (iter -- iter, next)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										3
									
								
								Python/executor_cases.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								Python/executor_cases.c.h
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -2201,8 +2201,7 @@
 | 
				
			||||||
            _PyListIterObject *it = (_PyListIterObject *)iter;
 | 
					            _PyListIterObject *it = (_PyListIterObject *)iter;
 | 
				
			||||||
            assert(Py_TYPE(iter) == &PyListIter_Type);
 | 
					            assert(Py_TYPE(iter) == &PyListIter_Type);
 | 
				
			||||||
            PyListObject *seq = it->it_seq;
 | 
					            PyListObject *seq = it->it_seq;
 | 
				
			||||||
            if (seq == NULL) goto deoptimize;
 | 
					            if ((size_t)it->it_index >= (size_t)PyList_GET_SIZE(seq)) goto deoptimize;
 | 
				
			||||||
            if (it->it_index >= PyList_GET_SIZE(seq)) goto deoptimize;
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								Python/generated_cases.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								Python/generated_cases.c.h
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -2541,11 +2541,14 @@
 | 
				
			||||||
                assert(Py_TYPE(iter) == &PyListIter_Type);
 | 
					                assert(Py_TYPE(iter) == &PyListIter_Type);
 | 
				
			||||||
                STAT_INC(FOR_ITER, hit);
 | 
					                STAT_INC(FOR_ITER, hit);
 | 
				
			||||||
                PyListObject *seq = it->it_seq;
 | 
					                PyListObject *seq = it->it_seq;
 | 
				
			||||||
                if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) {
 | 
					                if ((size_t)it->it_index >= (size_t)PyList_GET_SIZE(seq)) {
 | 
				
			||||||
 | 
					                    it->it_index = -1;
 | 
				
			||||||
 | 
					                    #ifndef Py_GIL_DISABLED
 | 
				
			||||||
                    if (seq != NULL) {
 | 
					                    if (seq != NULL) {
 | 
				
			||||||
                        it->it_seq = NULL;
 | 
					                        it->it_seq = NULL;
 | 
				
			||||||
                        Py_DECREF(seq);
 | 
					                        Py_DECREF(seq);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    #endif
 | 
				
			||||||
                    Py_DECREF(iter);
 | 
					                    Py_DECREF(iter);
 | 
				
			||||||
                    STACK_SHRINK(1);
 | 
					                    STACK_SHRINK(1);
 | 
				
			||||||
                    /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */
 | 
					                    /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue