8000 closes bpo-34656: Avoid relying on signed overflow in _pickle memos. … · python/cpython@71a9c65 · GitHub
[go: up one dir, main page]

Skip to content

Commit 71a9c65

Browse files
closes bpo-34656: Avoid relying on signed overflow in _pickle memos. (GH-9261)
(cherry picked from commit a4ae828) Co-authored-by: Benjamin Peterson <benjamin@python.org>
1 parent 6c9e109 commit 71a9c65

File tree

1 file changed

+31
-31
lines changed

1 file changed

+31
-31
lines changed

Modules/_pickle.c

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -596,9 +596,9 @@ typedef struct {
596596
} PyMemoEntry;
597597

598598
typedef struct {
599-
Py_ssize_t mt_mask;
600-
Py_ssize_t mt_used;
601-
Py_ssize_t mt_allocated;
599+
size_t mt_mask;
600+
size_t mt_used;
601+
size_t mt_allocated;
602602
PyMemoEntry *mt_table;
603603
} PyMemoTable;
604604

@@ -644,8 +644,8 @@ typedef struct UnpicklerObject {
644644
/* The unpickler memo is just an array of PyObject *s. Using a dict
645645
is unnecessary, since the keys are contiguous ints. */
646646
PyObject **memo;
647-
Py_ssize_t memo_size; /* Capacity of the memo array */
648-
Py_ssize_t memo_len; /* Number of objects in the memo */
647+
size_t memo_size; /* Capacity of the memo array */
648+
size_t memo_len; /* Number of objects in the memo */
649649

650650
PyObject *pers_func; /* persistent_load() method, can be NULL. */
651651
PyObject *pers_func_self; /* borrowed reference to self if pers_func
@@ -731,7 +731,6 @@ PyMemoTable_New(void)
731731
static PyMemoTable *
732732
PyMemoTable_Copy(PyMemoTable *self)
733733
{
734-
Py_ssize_t i;
735734
PyMemoTable *new = PyMemoTable_New();
736735
if (new == NULL)
737736
return NULL;
@@ -748,7 +747,7 @@ PyMemoTable_Copy(PyMemoTable *self)
748747
PyErr_NoMemory();
749748
return NULL;
750749
}
751-
for (i = 0; i < self->mt_allocated; i++) {
750+
for (size_t i = 0; i < self->mt_allocated; i++) {
752751
Py_XINCREF(self->mt_table[i].me_key);
753752
}
754753
memcpy(new->mt_table, self->mt_table,
@@ -794,7 +793,7 @@ _PyMemoTable_Lookup(PyMemoTable *self, PyObject *key)
794793
{
795794
size_t i;
796795
size_t perturb;
797-
size_t mask = (size_t)self->mt_mask;
796+
size_t mask = self->mt_mask;
798797
PyMemoEntry *table = self->mt_table;
799798
PyMemoEntry *entry;
800799
Py_hash_t hash = (Py_hash_t)key >> 3;
@@ -816,22 +815,24 @@ _PyMemoTable_Lookup(PyMemoTable *self, PyObject *key)
816815

817816
/* Returns -1 on failure, 0 on success. */
818817
static int
819-
_PyMemoTable_ResizeTable(PyMemoTable *self, Py_ssize_t min_size)
818+
_PyMemoTable_ResizeTable(PyMemoTable *self, size_t min_size)
820819
{
821820
PyMemoEntry *oldtable = NULL;
822821
PyMemoEntry *oldentry, *newentry;
823-
Py_ssize_t new_size = MT_MINSIZE;
824-
Py_ssize_t to_process;
822+
size_t new_size = MT_MINSIZE;
823+
size_t to_process;
825824

826825
assert(min_size > 0);
827826

828-
/* Find the smallest valid table size >= min_size. */
829-
while (new_size < min_size && new_size > 0)
830-
new_size <<= 1;
831-
if (new_size <= 0) {
827+
if (min_size > PY_SSIZE_T_MAX) {
832828
PyErr_NoMemory();
833829
return -1;
834830
}
831+
832+
/* Find the smallest valid table size >= min_size. */
833+
while (new_size < min_size) {
834+
new_size <<= 1;
835+
}
835836
/* new_size needs to be a power of two. */
836837
assert((new_size & (new_size - 1)) == 0);
837838

@@ -904,10 +905,12 @@ PyMemoTable_Set(PyMemoTable *self, PyObject *key, Py_ssize_t value)
904905
* Very large memo tables (over 50K items) use doubling instead.
905906
* This may help applications with severe memory constraints.
906907
*/
907-
if (!(self->mt_used * 3 >= (self->mt_mask + 1) * 2))
908+
if (SIZE_MAX / 3 >= self->mt_used && self->mt_used * 3 < self->mt_allocated * 2) {
908909
return 0;
909-
return _PyMemoTable_ResizeTable(self,
910-
(self->mt_used > 50000 ? 2 : 4) * self->mt_used);
910+
}
911+
// self->mt_used is always < PY_SSIZE_T_MAX, so this can't overflow.
912+
size_t desired_size = (self->mt_used > 50000 ? 2 : 4) * self->mt_used;
913+
return _PyMemoTable_ResizeTable(self, desired_size);
911914
}
912915

913916
#undef MT_MINSIZE
@@ -1352,9 +1355,9 @@ _Unpickler_Readline(UnpicklerObject *self, char **result)
13521355
/* Returns -1 (with an exception set) on failure, 0 on success. The memo array
13531356
will be modified in place. */
13541357
static int
1355-
_Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t new_size)
1358+
_Unpickler_ResizeMemoList(UnpicklerObject *self, size_t new_size)
13561359
{
1357-
Py_ssize_t i;
1360+
size_t i;
13581361

13591362
assert(new_size > self->memo_size);
13601363

@@ -1373,9 +1376,9 @@ _Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t new_size)
13731376

13741377
/* Returns NULL if idx is out of bounds. */
13751378
static PyObject *
1376-
_Unpickler_MemoGet(UnpicklerObject *self, Py_ssize_t idx)
1379+
_Unpickler_MemoGet(UnpicklerObject *self, size_t idx)
13771380
{
1378-
if (idx < 0 || idx >= self->memo_size)
1381+
if (idx >= self->memo_size)
13791382
return NULL;
13801383

13811384
return self->memo[idx];
@@ -1384,7 +1387,7 @@ _Unpickler_MemoGet(UnpicklerObject *self, Py_ssize_t idx)
13841387
/* Returns -1 (with an exception set) on failure, 0 on success.
13851388
This takes its own reference to `value`. */
13861389
static int
1387-
_Unpickler_MemoPut(UnpicklerObject *self, Py_ssize_t idx, PyObject *value)
1390+
_Unpickler_MemoPut(UnpicklerObject *self, size_t idx, PyObject *value)
13881391
{
13891392
PyObject *old_item;
13901393

@@ -4328,14 +4331,13 @@ static PyObject *
43284331
_pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self)
43294332
/*[clinic end generated code: output=bb83a919d29225ef input=b73043485ac30b36]*/
43304333
{
4331-
Py_ssize_t i;
43324334
PyMemoTable *memo;
43334335
PyObject *new_memo = PyDict_New();
43344336
if (new_memo == NULL)
43354337
return NULL;
43364338

43374339
memo = self->pickler->memo;
4338-
for (i = 0; i < memo->mt_allocated; ++i) {
4340+
for (size_t i = 0; i < memo->mt_allocated; ++i) {
43394341
PyMemoEntry entry = memo->mt_table[i];
43404342
if (entry.me_key != NULL) {
43414343
int status;
@@ -6764,7 +6766,7 @@ static PyObject *
67646766
_pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self)
67656767
/*[clinic end generated code: output=e12af7e9bc1e4c77 input=97769247ce032c1d]*/
67666768
{
6767-
Py_ssize_t i;
6769+
size_t i;
67686770
PyObject *new_memo = PyDict_New();
67696771
if (new_memo == NULL)
67706772
return NULL;
@@ -6915,8 +6917,7 @@ static int
69156917
Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
69166918
{
69176919
PyObject **new_memo;
6918-
Py_ssize_t new_memo_size = 0;
6919-
Py_ssize_t i;
6920+
size_t new_memo_size = 0;
69206921

69216922
if (obj == NULL) {
69226923
PyErr_SetString(PyExc_TypeError,
@@ -6933,7 +6934,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
69336934
if (new_memo == NULL)
69346935
return -1;
69356936

6936-
for (i = 0; i < new_memo_size; i++) {
6937+
for (size_t i = 0; i < new_memo_size; i++) {
69376938
Py_XINCREF(unpickler->memo[i]);
69386939
new_memo[i] = unpickler->memo[i];
69396940
}
@@ -6981,8 +6982,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
69816982

69826983
error:
69836984
if (new_memo_size) {
6984-
i = new_memo_size;
6985-
while (--i >= 0) {
6985+
for (size_t i = new_memo_size - 1; i != SIZE_MAX; i--) {
69866986
Py_XDECREF(new_memo[i]);
69876987
}
69886988
PyMem_FREE(new_memo);

0 commit comments

Comments
 (0)
0