Skip to content

Commit 3463f06

Browse files
committed
PYTHON-2191 Fix buffer leak added in 021adc5
1 parent 643e648 commit 3463f06

File tree

1 file changed

+57
-93
lines changed

1 file changed

+57
-93
lines changed

pymongo/_cmessagemodule.c

Lines changed: 57 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,9 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) {
190190
unsigned char continue_on_error;
191191
codec_options_t options;
192192
PyObject* last_error_args;
193-
buffer_t buffer;
193+
buffer_t buffer = NULL;
194194
int length_location, message_length;
195-
PyObject* result;
195+
PyObject* result = NULL;
196196

197197
if (!PyArg_ParseTuple(args, "et#ObbObO&",
198198
"utf-8",
@@ -209,9 +209,7 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) {
209209
}
210210
buffer = buffer_new();
211211
if (!buffer) {
212-
destroy_codec_options(&options);
213-
PyMem_Free(collection_name);
214-
return NULL;
212+
goto fail;
215213
}
216214

217215
length_location = init_insert_buffer(buffer,
@@ -221,10 +219,7 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) {
221219
collection_name_length,
222220
0);
223221
if (length_location == -1) {
224-
destroy_codec_options(&options);
225-
PyMem_Free(collection_name);
226-
buffer_free(buffer);
227-
return NULL;
222+
goto fail;
228223
}
229224

230225
iterator = PyObject_GetIter(docs);
@@ -234,21 +229,15 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) {
234229
PyErr_SetString(InvalidOperation, "input is not iterable");
235230
Py_DECREF(InvalidOperation);
236231
}
237-
destroy_codec_options(&options);
238-
buffer_free(buffer);
239-
PyMem_Free(collection_name);
240-
return NULL;
232+
goto fail;
241233
}
242234
while ((doc = PyIter_Next(iterator)) != NULL) {
243235
before = buffer_get_position(buffer);
244236
if (!write_dict(state->_cbson, buffer, doc, check_keys,
245237
&options, 1)) {
246238
Py_DECREF(doc);
247239
Py_DECREF(iterator);
248-
destroy_codec_options(&options);
249-
buffer_free(buffer);
250-
PyMem_Free(collection_name);
251-
return NULL;
240+
goto fail;
252241
}
253242
Py_DECREF(doc);
254243
cur_size = buffer_get_position(buffer) - before;
@@ -257,10 +246,7 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) {
257246
Py_DECREF(iterator);
258247

259248
if (PyErr_Occurred()) {
260-
destroy_codec_options(&options);
261-
buffer_free(buffer);
262-
PyMem_Free(collection_name);
263-
return NULL;
249+
goto fail;
264250
}
265251

266252
if (!max_size) {
@@ -269,10 +255,7 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) {
269255
PyErr_SetString(InvalidOperation, "cannot do an empty bulk insert");
270256
Py_DECREF(InvalidOperation);
271257
}
272-
destroy_codec_options(&options);
273-
buffer_free(buffer);
274-
PyMem_Free(collection_name);
275-
return NULL;
258+
goto fail;
276259
}
277260

278261
message_length = buffer_get_position(buffer) - length_location;
@@ -282,22 +265,21 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) {
282265
if (safe) {
283266
if (!add_last_error(self, buffer, request_id, collection_name,
284267
collection_name_length, &options, last_error_args)) {
285-
destroy_codec_options(&options);
286-
buffer_free(buffer);
287-
PyMem_Free(collection_name);
288-
return NULL;
268+
goto fail;
289269
}
290270
}
291271

292-
PyMem_Free(collection_name);
293-
294272
/* objectify buffer */
295273
result = Py_BuildValue("i" BYTES_FORMAT_STRING "i", request_id,
296274
buffer_get_buffer(buffer),
297275
(Py_ssize_t)buffer_get_position(buffer),
298276
max_size);
277+
fail:
278+
PyMem_Free(collection_name);
299279
destroy_codec_options(&options);
300-
buffer_free(buffer);
280+
if (buffer) {
281+
buffer_free(buffer);
282+
}
301283
return result;
302284
}
303285

@@ -318,9 +300,9 @@ static PyObject* _cbson_update_message(PyObject* self, PyObject* args) {
318300
codec_options_t options;
319301
PyObject* last_error_args;
320302
int flags;
321-
buffer_t buffer;
303+
buffer_t buffer = NULL;
322304
int length_location, message_length;
323-
PyObject* result;
305+
PyObject* result = NULL;
324306

325307
if (!PyArg_ParseTuple(args, "et#bbOObObO&",
326308
"utf-8",
@@ -341,17 +323,13 @@ static PyObject* _cbson_update_message(PyObject* self, PyObject* args) {
341323
}
342324
buffer = buffer_new();
343325
if (!buffer) {
344-
destroy_codec_options(&options);
345-
PyMem_Free(collection_name);
346-
return NULL;
326+
goto fail;
347327
}
348328

349329
// save space for message length
350330
length_location = buffer_save_space(buffer, 4);
351331
if (length_location == -1) {
352-
destroy_codec_options(&options);
353-
PyMem_Free(collection_name);
354-
return NULL;
332+
goto fail;
355333
}
356334
if (!buffer_write_int32(buffer, (int32_t)request_id) ||
357335
!buffer_write_bytes(buffer,
@@ -363,28 +341,19 @@ static PyObject* _cbson_update_message(PyObject* self, PyObject* args) {
363341
collection_name,
364342
collection_name_length + 1) ||
365343
!buffer_write_int32(buffer, (int32_t)flags)) {
366-
destroy_codec_options(&options);
367-
buffer_free(buffer);
368-
PyMem_Free(collection_name);
369-
return NULL;
344+
goto fail;
370345
}
371346

372347
before = buffer_get_position(buffer);
373348
if (!write_dict(state->_cbson, buffer, spec, 0, &options, 1)) {
374-
destroy_codec_options(&options);
375-
buffer_free(buffer);
376-
PyMem_Free(collection_name);
377-
return NULL;
349+
goto fail;
378350
}
379351
max_size = buffer_get_position(buffer) - before;
380352

381353
before = buffer_get_position(buffer);
382354
if (!write_dict(state->_cbson, buffer, doc, check_keys,
383355
&options, 1)) {
384-
destroy_codec_options(&options);
385-
buffer_free(buffer);
386-
PyMem_Free(collection_name);
387-
return NULL;
356+
goto fail;
388357
}
389358
cur_size = buffer_get_position(buffer) - before;
390359
max_size = (cur_size > max_size) ? cur_size : max_size;
@@ -396,22 +365,21 @@ static PyObject* _cbson_update_message(PyObject* self, PyObject* args) {
396365
if (safe) {
397366
if (!add_last_error(self, buffer, request_id, collection_name,
398367
collection_name_length, &options, last_error_args)) {
399-
destroy_codec_options(&options);
400-
buffer_free(buffer);
401-
PyMem_Free(collection_name);
402-
return NULL;
368+
goto fail;
403369
}
404370
}
405371

406-
PyMem_Free(collection_name);
407-
408372
/* objectify buffer */
409373
result = Py_BuildValue("i" BYTES_FORMAT_STRING "i", request_id,
410374
buffer_get_buffer(buffer),
411375
(Py_ssize_t)buffer_get_position(buffer),
412376
max_size);
377+
fail:
378+
PyMem_Free(collection_name);
413379
destroy_codec_options(&options);
414-
buffer_free(buffer);
380+
if (buffer) {
381+
buffer_free(buffer);
382+
}
415383
return result;
416384
}
417385

@@ -430,7 +398,7 @@ static PyObject* _cbson_query_message(PyObject* self, PyObject* args) {
430398
PyObject* query;
431399
PyObject* field_selector;
432400
codec_options_t options;
433-
buffer_t buffer;
401+
buffer_t buffer = NULL;
434402
int length_location, message_length;
435403
unsigned char check_keys = 0;
436404
PyObject* result = NULL;
@@ -448,17 +416,13 @@ static PyObject* _cbson_query_message(PyObject* self, PyObject* args) {
448416
}
449417
buffer = buffer_new();
450418
if (!buffer) {
451-
destroy_codec_options(&options);
452-
PyMem_Free(collection_name);
453-
return NULL;
419+
goto fail;
454420
}
455421

456422
// save space for message length
457423
length_location = buffer_save_space(buffer, 4);
458424
if (length_location == -1) {
459-
destroy_codec_options(&options);
460-
PyMem_Free(collection_name);
461-
return NULL;
425+
goto fail;
462426
}
463427

464428
/* Pop $clusterTime from dict and write it at the end, avoiding an error
@@ -547,11 +511,12 @@ static PyObject* _cbson_query_message(PyObject* self, PyObject* args) {
547511
buffer_get_buffer(buffer),
548512
(Py_ssize_t)buffer_get_position(buffer),
549513
max_size);
550-
551514
fail:
552515
PyMem_Free(collection_name);
553516
destroy_codec_options(&options);
554-
buffer_free(buffer);
517+
if (buffer) {
518+
buffer_free(buffer);
519+
}
555520
Py_XDECREF(cluster_time);
556521
return result;
557522
}
@@ -563,9 +528,9 @@ static PyObject* _cbson_get_more_message(PyObject* self, PyObject* args) {
563528
Py_ssize_t collection_name_length;
564529
int num_to_return;
565530
long long cursor_id;
566-
buffer_t buffer;
531+
buffer_t buffer = NULL;
567532
int length_location, message_length;
568-
PyObject* result;
533+
PyObject* result = NULL;
569534

570535
if (!PyArg_ParseTuple(args, "et#iL",
571536
"utf-8",
@@ -577,15 +542,13 @@ static PyObject* _cbson_get_more_message(PyObject* self, PyObject* args) {
577542
}
578543
buffer = buffer_new();
579544
if (!buffer) {
580-
PyMem_Free(collection_name);
581-
return NULL;
545+
goto fail;
582546
}
583547

584548
// save space for message length
585549
length_location = buffer_save_space(buffer, 4);
586550
if (length_location == -1) {
587-
PyMem_Free(collection_name);
588-
return NULL;
551+
goto fail;
589552
}
590553
if (!buffer_write_int32(buffer, (int32_t)request_id) ||
591554
!buffer_write_bytes(buffer,
@@ -597,13 +560,9 @@ static PyObject* _cbson_get_more_message(PyObject* self, PyObject* args) {
597560
collection_name_length + 1) ||
598561
!buffer_write_int32(buffer, (int32_t)num_to_return) ||
599562
!buffer_write_int64(buffer, (int64_t)cursor_id)) {
600-
buffer_free(buffer);
601-
PyMem_Free(collection_name);
602-
return NULL;
563+
goto fail;
603564
}
604565

605-
PyMem_Free(collection_name);
606-
607566
message_length = buffer_get_position(buffer) - length_location;
608567
buffer_write_int32_at_position(
609568
buffer, length_location, (int32_t)message_length);
@@ -612,7 +571,11 @@ static PyObject* _cbson_get_more_message(PyObject* self, PyObject* args) {
612571
result = Py_BuildValue("i" BYTES_FORMAT_STRING, request_id,
613572
buffer_get_buffer(buffer),
614573
(Py_ssize_t)buffer_get_position(buffer));
615-
buffer_free(buffer);
574+
fail:
575+
PyMem_Free(collection_name);
576+
if (buffer) {
577+
buffer_free(buffer);
578+
}
616579
return result;
617580
}
618581

@@ -634,7 +597,7 @@ static PyObject* _cbson_op_msg(PyObject* self, PyObject* args) {
634597
PyObject* doc;
635598
unsigned char check_keys = 0;
636599
codec_options_t options;
637-
buffer_t buffer;
600+
buffer_t buffer = NULL;
638601
int length_location, message_length;
639602
int total_size = 0;
640603
int max_doc_size = 0;
@@ -655,54 +618,54 @@ static PyObject* _cbson_op_msg(PyObject* self, PyObject* args) {
655618
}
656619
buffer = buffer_new();
657620
if (!buffer) {
658-
goto bufferfail;
621+
goto fail;
659622
}
660623

661624
// save space for message length
662625
length_location = buffer_save_space(buffer, 4);
663626
if (length_location == -1) {
664-
goto bufferfail;
627+
goto fail;
665628
}
666629
if (!buffer_write_int32(buffer, (int32_t)request_id) ||
667630
!buffer_write_bytes(buffer,
668631
"\x00\x00\x00\x00" /* responseTo */
669632
"\xdd\x07\x00\x00" /* 2013 */, 8)) {
670-
goto encodefail;
633+
goto fail;
671634
}
672635

673636
if (!buffer_write_int32(buffer, (int32_t)flags) ||
674637
!buffer_write_bytes(buffer, "\x00", 1) /* Payload type 0 */) {
675-
goto encodefail;
638+
goto fail;
676639
}
677640
total_size = write_dict(state->_cbson, buffer, command, 0,
678641
&options, 1);
679642
if (!total_size) {
680-
goto encodefail;
643+
goto fail;
681644
}
682645

683646
if (identifier_length) {
684647
int payload_one_length_location, payload_length;
685648
/* Payload type 1 */
686649
if (!buffer_write_bytes(buffer, "\x01", 1)) {
687-
goto encodefail;
650+
goto fail;
688651
}
689652
/* save space for payload 0 length */
690653
payload_one_length_location = buffer_save_space(buffer, 4);
691654
/* C string identifier */
692655
if (!buffer_write_bytes_ssize_t(buffer, identifier, identifier_length + 1)) {
693-
goto encodefail;
656+
goto fail;
694657
}
695658
iterator = PyObject_GetIter(docs);
696659
if (iterator == NULL) {
697-
goto encodefail;
660+
goto fail;
698661
}
699662
while ((doc = PyIter_Next(iterator)) != NULL) {
700663
int encoded_doc_size = write_dict(
701664
state->_cbson, buffer, doc, check_keys,
702665
&options, 1);
703666
if (!encoded_doc_size) {
704667
Py_CLEAR(doc);
705-
goto encodefail;
668+
goto fail;
706669
}
707670
if (encoded_doc_size > max_doc_size) {
708671
max_doc_size = encoded_doc_size;
@@ -726,10 +689,11 @@ static PyObject* _cbson_op_msg(PyObject* self, PyObject* args) {
726689
(Py_ssize_t)buffer_get_position(buffer),
727690
total_size,
728691
max_doc_size);
729-
encodefail:
692+
fail:
730693
Py_XDECREF(iterator);
731-
buffer_free(buffer);
732-
bufferfail:
694+
if (buffer) {
695+
buffer_free(buffer);
696+
}
733697
PyMem_Free(identifier);
734698
destroy_codec_options(&options);
735699
return result;

0 commit comments

Comments
 (0)