mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #25135: Avoid possible reentrancy issues in deque_clear.
This commit is contained in:
parent
03c59b9bef
commit
bf49fee125
2 changed files with 62 additions and 3 deletions
|
@ -27,6 +27,9 @@ Library
|
||||||
respects the letter case given by the user. This restores the ability to
|
respects the letter case given by the user. This restores the ability to
|
||||||
write encoding names in uppercase like "UTF-8", which worked in Python 2.
|
write encoding names in uppercase like "UTF-8", which worked in Python 2.
|
||||||
|
|
||||||
|
- Issue #25135: Make deque_clear() safer by emptying the deque before clearing.
|
||||||
|
This helps avoid possible reentrancy issues.
|
||||||
|
|
||||||
- Issue #19143: platform module now reads Windows version from kernel32.dll to
|
- Issue #19143: platform module now reads Windows version from kernel32.dll to
|
||||||
avoid compatibility shims.
|
avoid compatibility shims.
|
||||||
|
|
||||||
|
|
|
@ -1038,16 +1038,72 @@ PyDoc_STRVAR(remove_doc,
|
||||||
static void
|
static void
|
||||||
deque_clear(dequeobject *deque)
|
deque_clear(dequeobject *deque)
|
||||||
{
|
{
|
||||||
|
block *b;
|
||||||
|
block *prevblock;
|
||||||
|
block *leftblock;
|
||||||
|
Py_ssize_t leftindex;
|
||||||
|
Py_ssize_t n;
|
||||||
PyObject *item;
|
PyObject *item;
|
||||||
|
|
||||||
|
/* During the process of clearing a deque, decrefs can cause the
|
||||||
|
deque to mutate. To avoid fatal confusion, we have to make the
|
||||||
|
deque empty before clearing the blocks and never refer to
|
||||||
|
anything via deque->ref while clearing. (This is the same
|
||||||
|
technique used for clearing lists, sets, and dicts.)
|
||||||
|
|
||||||
|
Making the deque empty requires allocating a new empty block. In
|
||||||
|
the unlikely event that memory is full, we fall back to an
|
||||||
|
alternate method that doesn't require a new block. Repeating
|
||||||
|
pops in a while-loop is slower, possibly re-entrant (and a clever
|
||||||
|
adversary could cause it to never terminate).
|
||||||
|
*/
|
||||||
|
|
||||||
|
b = newblock(0);
|
||||||
|
if (b == NULL) {
|
||||||
|
PyErr_Clear();
|
||||||
|
goto alternate_method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember the old size, leftblock, and leftindex */
|
||||||
|
leftblock = deque->leftblock;
|
||||||
|
leftindex = deque->leftindex;
|
||||||
|
n = Py_SIZE(deque);
|
||||||
|
|
||||||
|
/* Set the deque to be empty using the newly allocated block */
|
||||||
|
MARK_END(b->leftlink);
|
||||||
|
MARK_END(b->rightlink);
|
||||||
|
Py_SIZE(deque) = 0;
|
||||||
|
deque->leftblock = b;
|
||||||
|
deque->rightblock = b;
|
||||||
|
deque->leftindex = CENTER + 1;
|
||||||
|
deque->rightindex = CENTER;
|
||||||
|
deque->state++;
|
||||||
|
|
||||||
|
/* Now the old size, leftblock, and leftindex are disconnected from
|
||||||
|
the empty deque and we can use them to decref the pointers.
|
||||||
|
*/
|
||||||
|
while (n--) {
|
||||||
|
item = leftblock->data[leftindex];
|
||||||
|
Py_DECREF(item);
|
||||||
|
leftindex++;
|
||||||
|
if (leftindex == BLOCKLEN && n) {
|
||||||
|
CHECK_NOT_END(leftblock->rightlink);
|
||||||
|
prevblock = leftblock;
|
||||||
|
leftblock = leftblock->rightlink;
|
||||||
|
leftindex = 0;
|
||||||
|
freeblock(prevblock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK_END(leftblock->rightlink);
|
||||||
|
freeblock(leftblock);
|
||||||
|
return;
|
||||||
|
|
||||||
|
alternate_method:
|
||||||
while (Py_SIZE(deque)) {
|
while (Py_SIZE(deque)) {
|
||||||
item = deque_pop(deque, NULL);
|
item = deque_pop(deque, NULL);
|
||||||
assert (item != NULL);
|
assert (item != NULL);
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
}
|
}
|
||||||
assert(deque->leftblock == deque->rightblock);
|
|
||||||
assert(deque->leftindex - 1 == deque->rightindex);
|
|
||||||
assert(Py_SIZE(deque) == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue