Skip to content

Commit b14ab44

Browse files
bpo-34395: Fix memory leaks caused by incautious usage of PyMem_Resize(). (GH-8756)
(cherry picked from commit 67b9cc8) Co-authored-by: Sergey Fedoseev <[email protected]>
1 parent eeca87c commit b14ab44

File tree

2 files changed

+22
-42
lines changed

2 files changed

+22
-42
lines changed

Modules/_csv.c

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -561,25 +561,17 @@ parse_save_field(ReaderObj *self)
561561
static int
562562
parse_grow_buff(ReaderObj *self)
563563
{
564-
if (self->field_size == 0) {
565-
self->field_size = 4096;
566-
if (self->field != NULL)
567-
PyMem_Free(self->field);
568-
self->field = PyMem_New(Py_UCS4, self->field_size);
569-
}
570-
else {
571-
Py_UCS4 *field = self->field;
572-
if (self->field_size > PY_SSIZE_T_MAX / 2) {
573-
PyErr_NoMemory();
574-
return 0;
575-
}
576-
self->field_size *= 2;
577-
self->field = PyMem_Resize(field, Py_UCS4, self->field_size);
578-
}
579-
if (self->field == NULL) {
564+
assert((size_t)self->field_size <= PY_SSIZE_T_MAX / sizeof(Py_UCS4));
565+
566+
Py_ssize_t field_size_new = self->field_size ? 2 * self->field_size : 4096;
567+
Py_UCS4 *field_new = self->field;
568+
PyMem_Resize(field_new, Py_UCS4, field_size_new);
569+
if (field_new == NULL) {
580570
PyErr_NoMemory();
581571
return 0;
582572
}
573+
self->field = field_new;
574+
self->field_size = field_size_new;
583575
return 1;
584576
}
585577

@@ -1095,31 +1087,18 @@ join_append_data(WriterObj *self, unsigned int field_kind, void *field_data,
10951087
static int
10961088
join_check_rec_size(WriterObj *self, Py_ssize_t rec_len)
10971089
{
1098-
1099-
if (rec_len < 0 || rec_len > PY_SSIZE_T_MAX - MEM_INCR) {
1100-
PyErr_NoMemory();
1101-
return 0;
1102-
}
1090+
assert(rec_len >= 0);
11031091

11041092
if (rec_len > self->rec_size) {
1105-
if (self->rec_size == 0) {
1106-
self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR;
1107-
if (self->rec != NULL)
1108-
PyMem_Free(self->rec);
1109-
self->rec = PyMem_New(Py_UCS4, self->rec_size);
1110-
}
1111-
else {
1112-
Py_UCS4* old_rec = self->rec;
1113-
1114-
self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR;
1115-
self->rec = PyMem_Resize(old_rec, Py_UCS4, self->rec_size);
1116-
if (self->rec == NULL)
1117-
PyMem_Free(old_rec);
1118-
}
1119-
if (self->rec == NULL) {
1093+
size_t rec_size_new = (size_t)(rec_len / MEM_INCR + 1) * MEM_INCR;
1094+
Py_UCS4 *rec_new = self->rec;
1095+
PyMem_Resize(rec_new, Py_UCS4, rec_size_new);
1096+
if (rec_new == NULL) {
11201097
PyErr_NoMemory();
11211098
return 0;
11221099
}
1100+
self->rec = rec_new;
1101+
self->rec_size = (Py_ssize_t)rec_size_new;
11231102
}
11241103
return 1;
11251104
}

Modules/_pickle.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,11 +1358,13 @@ _Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t new_size)
13581358

13591359
assert(new_size > self->memo_size);
13601360

1361-
PyMem_RESIZE(self->memo, PyObject *, new_size);
1362-
if (self->memo == NULL) {
1361+
PyObject **memo_new = self->memo;
1362+
PyMem_RESIZE(memo_new, PyObject *, new_size);
1363+
if (memo_new == NULL) {
13631364
PyErr_NoMemory();
13641365
return -1;
13651366
}
1367+
self->memo = memo_new;
13661368
for (i = self->memo_size; i < new_size; i++)
13671369
self->memo[i] = NULL;
13681370
self->memo_size = new_size;
@@ -6195,11 +6197,10 @@ load_mark(UnpicklerObject *self)
61956197
return -1;
61966198
}
61976199

6198-
if (self->marks == NULL)
6199-
self->marks = PyMem_NEW(Py_ssize_t, alloc);
6200-
else
6201-
PyMem_RESIZE(self->marks, Py_ssize_t, alloc);
6200+
Py_ssize_t *marks_old = self->marks;
6201+
PyMem_RESIZE(self->marks, Py_ssize_t, alloc);
62026202
if (self->marks == NULL) {
6203+
PyMem_FREE(marks_old);
62036204
self->marks_size = 0;
62046205
PyErr_NoMemory();
62056206
return -1;

0 commit comments

Comments
 (0)