Skip to content

Commit 643e648

Browse files
committed
PYTHON-2188 Raise ValueError instead of MemoryError when encoding exceeds 2GiB
1 parent 021adc5 commit 643e648

File tree

3 files changed

+23
-34
lines changed

3 files changed

+23
-34
lines changed

bson/_cbsonmodule.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@ static long long millis_from_datetime(PyObject* datetime) {
193193
/* Just make this compatible w/ the old API. */
194194
int buffer_write_bytes(buffer_t buffer, const char* data, int size) {
195195
if (buffer_write(buffer, data, size)) {
196-
PyErr_NoMemory();
197196
return 0;
198197
}
199198
return 1;
@@ -923,7 +922,6 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer,
923922
/* save space for length */
924923
length_location = buffer_save_space(buffer, 4);
925924
if (length_location == -1) {
926-
PyErr_NoMemory();
927925
Py_DECREF(scope);
928926
return 0;
929927
}
@@ -1121,7 +1119,6 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer,
11211119
/* save space for length */
11221120
length_location = buffer_save_space(buffer, 4);
11231121
if (length_location == -1) {
1124-
PyErr_NoMemory();
11251122
return 0;
11261123
}
11271124

@@ -1140,7 +1137,6 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer,
11401137
PyObject* item_value;
11411138

11421139
if (list_type_byte == -1) {
1143-
PyErr_NoMemory();
11441140
return 0;
11451141
}
11461142
INT2STRING(name, (int)i);
@@ -1454,7 +1450,6 @@ int write_pair(PyObject* self, buffer_t buffer, const char* name, int name_lengt
14541450

14551451
type_byte = buffer_save_space(buffer, 1);
14561452
if (type_byte == -1) {
1457-
PyErr_NoMemory();
14581453
return 0;
14591454
}
14601455
if (check_keys && !check_key_name(name, name_length)) {
@@ -1704,7 +1699,6 @@ int write_dict(PyObject* self, buffer_t buffer,
17041699

17051700
length_location = buffer_save_space(buffer, 4);
17061701
if (length_location == -1) {
1707-
PyErr_NoMemory();
17081702
return 0;
17091703
}
17101704

@@ -1808,7 +1802,6 @@ static PyObject* _cbson_dict_to_bson(PyObject* self, PyObject* args) {
18081802
buffer = buffer_new();
18091803
if (!buffer) {
18101804
destroy_codec_options(&options);
1811-
PyErr_NoMemory();
18121805
return NULL;
18131806
}
18141807

bson/buffer.c

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#include <stdlib.h>
1818
#include <string.h>
1919

20+
/* Include Python.h so we can set Python's error indicator. */
21+
#define PY_SSIZE_T_CLEAN
22+
#include "Python.h"
23+
2024
#include "buffer.h"
2125

2226
#define INITIAL_BUFFER_SIZE 256
@@ -27,12 +31,19 @@ struct buffer {
2731
int position;
2832
};
2933

34+
/* Set Python's error indicator to MemoryError.
35+
* Called after allocation failures. */
36+
static void set_memory_error() {
37+
PyErr_NoMemory();
38+
}
39+
3040
/* Allocate and return a new buffer.
31-
* Return NULL on allocation failure. */
41+
* Return NULL and sets MemoryError on allocation failure. */
3242
buffer_t buffer_new(void) {
3343
buffer_t buffer;
3444
buffer = (buffer_t)malloc(sizeof(struct buffer));
3545
if (buffer == NULL) {
46+
set_memory_error();
3647
return NULL;
3748
}
3849

@@ -41,6 +52,7 @@ buffer_t buffer_new(void) {
4152
buffer->buffer = (char*)malloc(sizeof(char) * INITIAL_BUFFER_SIZE);
4253
if (buffer->buffer == NULL) {
4354
free(buffer);
55+
set_memory_error();
4456
return NULL;
4557
}
4658

@@ -62,7 +74,7 @@ int buffer_free(buffer_t buffer) {
6274
}
6375

6476
/* Grow `buffer` to at least `min_length`.
65-
* Return non-zero on allocation failure. */
77+
* Return non-zero and sets MemoryError on allocation failure. */
6678
static int buffer_grow(buffer_t buffer, int min_length) {
6779
int old_size = 0;
6880
int size = buffer->size;
@@ -82,18 +94,22 @@ static int buffer_grow(buffer_t buffer, int min_length) {
8294
buffer->buffer = (char*)realloc(buffer->buffer, sizeof(char) * size);
8395
if (buffer->buffer == NULL) {
8496
free(old_buffer);
97+
set_memory_error();
8598
return 1;
8699
}
87100
buffer->size = size;
88101
return 0;
89102
}
90103

91104
/* Assure that `buffer` has at least `size` free bytes (and grow if needed).
92-
* Return non-zero on allocation failure. */
105+
* Return non-zero and sets MemoryError on allocation failure.
106+
* Return non-zero and sets ValueError if `size` would exceed 2GiB. */
93107
static int buffer_assure_space(buffer_t buffer, int size) {
94108
int new_size = buffer->position + size;
95109
/* Check for overflow. */
96110
if (new_size < buffer->position) {
111+
PyErr_SetString(PyExc_ValueError,
112+
"Document would overflow BSON size limit");
97113
return 1;
98114
}
99115

@@ -104,7 +120,8 @@ static int buffer_assure_space(buffer_t buffer, int size) {
104120
}
105121

106122
/* Save `size` bytes from the current position in `buffer` (and grow if needed).
107-
* Return offset for writing, or -1 on allocation failure. */
123+
* Return offset for writing, or -1 on failure.
124+
* Sets MemoryError or ValueError on failure. */
108125
buffer_position buffer_save_space(buffer_t buffer, int size) {
109126
int position = buffer->position;
110127
if (buffer_assure_space(buffer, size) != 0) {
@@ -115,7 +132,8 @@ buffer_position buffer_save_space(buffer_t buffer, int size) {
115132
}
116133

117134
/* Write `size` bytes from `data` to `buffer` (and grow if needed).
118-
* Return non-zero on allocation failure. */
135+
* Return non-zero on failure.
136+
* Sets MemoryError or ValueError on failure. */
119137
int buffer_write(buffer_t buffer, const char* data, int size) {
120138
if (buffer_assure_space(buffer, size) != 0) {
121139
return 1;

pymongo/_cmessagemodule.c

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ static int add_last_error(PyObject* self, buffer_t buffer,
8888

8989
message_start = buffer_save_space(buffer, 4);
9090
if (message_start == -1) {
91-
PyErr_NoMemory();
9291
return 0;
9392
}
9493
if (!buffer_write_int32(buffer, (int32_t)request_id) ||
@@ -109,7 +108,6 @@ static int add_last_error(PyObject* self, buffer_t buffer,
109108
/* save space for length */
110109
document_start = buffer_save_space(buffer, 4);
111110
if (document_start == -1) {
112-
PyErr_NoMemory();
113111
return 0;
114112
}
115113

@@ -154,7 +152,6 @@ static int init_insert_buffer(buffer_t buffer, int request_id, int options,
154152
/* Save space for message length */
155153
int length_location = buffer_save_space(buffer, 4);
156154
if (length_location == -1) {
157-
PyErr_NoMemory();
158155
return length_location;
159156
}
160157
if (!buffer_write_int32(buffer, (int32_t)request_id) ||
@@ -212,7 +209,6 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) {
212209
}
213210
buffer = buffer_new();
214211
if (!buffer) {
215-
PyErr_NoMemory();
216212
destroy_codec_options(&options);
217213
PyMem_Free(collection_name);
218214
return NULL;
@@ -346,7 +342,6 @@ static PyObject* _cbson_update_message(PyObject* self, PyObject* args) {
346342
buffer = buffer_new();
347343
if (!buffer) {
348344
destroy_codec_options(&options);
349-
PyErr_NoMemory();
350345
PyMem_Free(collection_name);
351346
return NULL;
352347
}
@@ -356,7 +351,6 @@ static PyObject* _cbson_update_message(PyObject* self, PyObject* args) {
356351
if (length_location == -1) {
357352
destroy_codec_options(&options);
358353
PyMem_Free(collection_name);
359-
PyErr_NoMemory();
360354
return NULL;
361355
}
362356
if (!buffer_write_int32(buffer, (int32_t)request_id) ||
@@ -454,7 +448,6 @@ static PyObject* _cbson_query_message(PyObject* self, PyObject* args) {
454448
}
455449
buffer = buffer_new();
456450
if (!buffer) {
457-
PyErr_NoMemory();
458451
destroy_codec_options(&options);
459452
PyMem_Free(collection_name);
460453
return NULL;
@@ -465,7 +458,6 @@ static PyObject* _cbson_query_message(PyObject* self, PyObject* args) {
465458
if (length_location == -1) {
466459
destroy_codec_options(&options);
467460
PyMem_Free(collection_name);
468-
PyErr_NoMemory();
469461
return NULL;
470462
}
471463

@@ -585,7 +577,6 @@ static PyObject* _cbson_get_more_message(PyObject* self, PyObject* args) {
585577
}
586578
buffer = buffer_new();
587579
if (!buffer) {
588-
PyErr_NoMemory();
589580
PyMem_Free(collection_name);
590581
return NULL;
591582
}
@@ -594,7 +585,6 @@ static PyObject* _cbson_get_more_message(PyObject* self, PyObject* args) {
594585
length_location = buffer_save_space(buffer, 4);
595586
if (length_location == -1) {
596587
PyMem_Free(collection_name);
597-
PyErr_NoMemory();
598588
return NULL;
599589
}
600590
if (!buffer_write_int32(buffer, (int32_t)request_id) ||
@@ -665,14 +655,12 @@ static PyObject* _cbson_op_msg(PyObject* self, PyObject* args) {
665655
}
666656
buffer = buffer_new();
667657
if (!buffer) {
668-
PyErr_NoMemory();
669658
goto bufferfail;
670659
}
671660

672661
// save space for message length
673662
length_location = buffer_save_space(buffer, 4);
674663
if (length_location == -1) {
675-
PyErr_NoMemory();
676664
goto bufferfail;
677665
}
678666
if (!buffer_write_int32(buffer, (int32_t)request_id) ||
@@ -879,7 +867,6 @@ static PyObject* _cbson_do_batched_insert(PyObject* self, PyObject* args) {
879867
buffer = buffer_new();
880868
if (!buffer) {
881869
destroy_codec_options(&options);
882-
PyErr_NoMemory();
883870
PyMem_Free(collection_name);
884871
return NULL;
885872
}
@@ -944,7 +931,6 @@ static PyObject* _cbson_do_batched_insert(PyObject* self, PyObject* args) {
944931
int message_start;
945932
buffer_t new_buffer = buffer_new();
946933
if (!new_buffer) {
947-
PyErr_NoMemory();
948934
goto iterfail;
949935
}
950936
message_start = init_insert_buffer(new_buffer,
@@ -1181,7 +1167,6 @@ _batched_op_msg(
11811167
/* Save space for size */
11821168
size_location = buffer_save_space(buffer, 4);
11831169
if (size_location == -1) {
1184-
PyErr_NoMemory();
11851170
return 0;
11861171
}
11871172

@@ -1325,7 +1310,6 @@ _cbson_encode_batched_op_msg(PyObject* self, PyObject* args) {
13251310
return NULL;
13261311
}
13271312
if (!(buffer = buffer_new())) {
1328-
PyErr_NoMemory();
13291313
destroy_codec_options(&options);
13301314
return NULL;
13311315
}
@@ -1381,13 +1365,11 @@ _cbson_batched_op_msg(PyObject* self, PyObject* args) {
13811365
return NULL;
13821366
}
13831367
if (!(buffer = buffer_new())) {
1384-
PyErr_NoMemory();
13851368
destroy_codec_options(&options);
13861369
return NULL;
13871370
}
13881371
/* Save space for message length and request id */
13891372
if ((buffer_save_space(buffer, 8)) == -1) {
1390-
PyErr_NoMemory();
13911373
goto fail;
13921374
}
13931375
if (!buffer_write_bytes(buffer,
@@ -1552,7 +1534,6 @@ _batched_write_command(
15521534
/* Save space for list document */
15531535
lst_len_loc = buffer_save_space(buffer, 4);
15541536
if (lst_len_loc == -1) {
1555-
PyErr_NoMemory();
15561537
return 0;
15571538
}
15581539

@@ -1672,7 +1653,6 @@ _cbson_encode_batched_write_command(PyObject* self, PyObject* args) {
16721653
return NULL;
16731654
}
16741655
if (!(buffer = buffer_new())) {
1675-
PyErr_NoMemory();
16761656
PyMem_Free(ns);
16771657
destroy_codec_options(&options);
16781658
return NULL;
@@ -1732,14 +1712,12 @@ _cbson_batched_write_command(PyObject* self, PyObject* args) {
17321712
return NULL;
17331713
}
17341714
if (!(buffer = buffer_new())) {
1735-
PyErr_NoMemory();
17361715
PyMem_Free(ns);
17371716
destroy_codec_options(&options);
17381717
return NULL;
17391718
}
17401719
/* Save space for message length and request id */
17411720
if ((buffer_save_space(buffer, 8)) == -1) {
1742-
PyErr_NoMemory();
17431721
goto fail;
17441722
}
17451723
if (!buffer_write_bytes(buffer,

0 commit comments

Comments
 (0)