From b1dc0a455a233a67feaef910a8e59999b8fc7d06 Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Thu, 16 Aug 2018 17:28:35 +0500 Subject: [PATCH 1/5] bpo-34395: Fix memory leaks in csv module. --- Modules/_csv.c | 54 ++++++++++++++++++++------------------------------ 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index ea7d08931c4593..9710fcf39d7b28 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -565,24 +565,21 @@ parse_save_field(ReaderObj *self) static int parse_grow_buff(ReaderObj *self) { - if (self->field_size == 0) { - self->field_size = 4096; - if (self->field != NULL) - PyMem_Free(self->field); - self->field = PyMem_Malloc(self->field_size); - } - else { - if (self->field_size > INT_MAX / 2) { - PyErr_NoMemory(); - return 0; - } - self->field_size *= 2; - self->field = PyMem_Realloc(self->field, self->field_size); + assert((unsigned)self->field_size <= INT_MAX); + + unsigned field_size_new = self->field_size ? 2 * (unsigned)self->field_size : 4096; + if (field_size_new > INT_MAX) { + PyErr_NoMemory(); + return 0; } - if (self->field == NULL) { + char *field_new = self->field; + PyMem_Resize(field_new, char, field_size_new); + if (field == NULL) { PyErr_NoMemory(); return 0; } + self->field = field_new; + self->field_size = (int)field_size_new; return 1; } @@ -1088,31 +1085,22 @@ join_append_data(WriterObj *self, char *field, int quote_empty, static int join_check_rec_size(WriterObj *self, int rec_len) { - - if (rec_len < 0 || rec_len > INT_MAX - MEM_INCR) { - PyErr_NoMemory(); - return 0; - } + assert(rec_len >= 0); if (rec_len > self->rec_size) { - if (self->rec_size == 0) { - self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR; - if (self->rec != NULL) - PyMem_Free(self->rec); - self->rec = PyMem_Malloc(self->rec_size); - } - else { - char *old_rec = self->rec; - - self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR; - self->rec = PyMem_Realloc(self->rec, self->rec_size); - if (self->rec == NULL) - PyMem_Free(old_rec); + unsigned rec_size_new = (unsigned)(rec_len / MEM_INCR + 1) * MEM_INCR; + if (rec_size_new > INT_MAX) { + PyErr_NoMemory(); + return 0; } - if (self->rec == NULL) { + char *rec_new = self->rec; + PyMem_Resize(rec_new, char, rec_size_new); + if (rec_new == NULL) { PyErr_NoMemory(); return 0; } + self->rec = rec_new; + self->rec_size = (int)rec_size_new; } return 1; } From 5315d2fa839bdeea03b7b435943a5a669652048c Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Thu, 16 Aug 2018 17:57:55 +0500 Subject: [PATCH 2/5] Fix var name. --- Modules/_csv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index 9710fcf39d7b28..637ce980483864 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -574,7 +574,7 @@ parse_grow_buff(ReaderObj *self) } char *field_new = self->field; PyMem_Resize(field_new, char, field_size_new); - if (field == NULL) { + if (field_new == NULL) { PyErr_NoMemory(); return 0; } From 458c8b3379881393fa656ea93583a9627f735cb7 Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Thu, 16 Aug 2018 21:04:40 +0500 Subject: [PATCH 3/5] Move variable declarations for C89 compliance. --- Modules/_csv.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index 637ce980483864..521f610e1aa3f5 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -565,14 +565,17 @@ parse_save_field(ReaderObj *self) static int parse_grow_buff(ReaderObj *self) { + unsigned field_size_new; + char *field_new + assert((unsigned)self->field_size <= INT_MAX); - unsigned field_size_new = self->field_size ? 2 * (unsigned)self->field_size : 4096; + field_size_new = self->field_size ? 2 * (unsigned)self->field_size : 4096; if (field_size_new > INT_MAX) { PyErr_NoMemory(); return 0; } - char *field_new = self->field; + field_new = self->field; PyMem_Resize(field_new, char, field_size_new); if (field_new == NULL) { PyErr_NoMemory(); @@ -1085,15 +1088,18 @@ join_append_data(WriterObj *self, char *field, int quote_empty, static int join_check_rec_size(WriterObj *self, int rec_len) { + unsigned rec_size_new; + char *rec_new; + assert(rec_len >= 0); if (rec_len > self->rec_size) { - unsigned rec_size_new = (unsigned)(rec_len / MEM_INCR + 1) * MEM_INCR; + rec_size_new = (unsigned)(rec_len / MEM_INCR + 1) * MEM_INCR; if (rec_size_new > INT_MAX) { PyErr_NoMemory(); return 0; } - char *rec_new = self->rec; + rec_new = self->rec; PyMem_Resize(rec_new, char, rec_size_new); if (rec_new == NULL) { PyErr_NoMemory(); From d83927af15483d60634fb635f41649b98a26a2f3 Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Thu, 16 Aug 2018 21:24:35 +0500 Subject: [PATCH 4/5] Add forgotten semicolon. --- Modules/_csv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index 521f610e1aa3f5..9a59d8a5f7b702 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -566,7 +566,7 @@ static int parse_grow_buff(ReaderObj *self) { unsigned field_size_new; - char *field_new + char *field_new; assert((unsigned)self->field_size <= INT_MAX); From 9ebc70b929bc4e37db2c9f4089f8757fe1ca5392 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 16 Aug 2018 20:42:53 +0300 Subject: [PATCH 5/5] Use PyMem_Realloc(). --- Modules/_csv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index 9a59d8a5f7b702..88e3e9065842e8 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -575,8 +575,7 @@ parse_grow_buff(ReaderObj *self) PyErr_NoMemory(); return 0; } - field_new = self->field; - PyMem_Resize(field_new, char, field_size_new); + field_new = (char *)PyMem_Realloc(self->field, field_size_new); if (field_new == NULL) { PyErr_NoMemory(); return 0; @@ -1099,8 +1098,7 @@ join_check_rec_size(WriterObj *self, int rec_len) PyErr_NoMemory(); return 0; } - rec_new = self->rec; - PyMem_Resize(rec_new, char, rec_size_new); + rec_new = (char *)PyMem_Realloc(self->rec, rec_size_new); if (rec_new == NULL) { PyErr_NoMemory(); return 0;