Skip to content

Commit 6bc50a4

Browse files
committed
Cleaned up object inflation. Added more error checking.
1 parent 6438d5d commit 6bc50a4

File tree

2 files changed

+108
-100
lines changed

2 files changed

+108
-100
lines changed

maxminddb.c

Lines changed: 104 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ static PyObject *MaxMindDB_error;
1111

1212
typedef struct {
1313
PyObject_HEAD /* no semicolon */
14-
MMDB_s * mmdb;
14+
MMDB_s *mmdb;
1515
} Reader_obj;
1616

1717
typedef struct {
@@ -27,17 +27,10 @@ typedef struct {
2727
PyObject *record_size;
2828
} Metadata_obj;
2929

30-
static const MMDB_entry_data_list_s *handle_entry_data_list(
31-
const MMDB_entry_data_list_s *entry_data_list,
32-
PyObject **py_obj);
33-
static const MMDB_entry_data_list_s *handle_map(
34-
const MMDB_entry_data_list_s *entry_data_list,
35-
PyObject **py_obj);
36-
static const MMDB_entry_data_list_s *handle_array(
37-
const MMDB_entry_data_list_s *entry_data_list,
38-
PyObject **py_obj);
39-
static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
40-
PyObject **py_obj);
30+
static PyObject *from_entry_data_list(MMDB_entry_data_list_s **entry_data_list);
31+
static PyObject *from_map(MMDB_entry_data_list_s **entry_data_list);
32+
static PyObject *from_array(MMDB_entry_data_list_s **entry_data_list);
33+
static PyObject *from_uint128(const MMDB_entry_data_list_s *entry_data_list);
4134

4235
#if PY_MAJOR_VERSION >= 3
4336
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_ ## name(void)
@@ -54,7 +47,7 @@ static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
5447
# define UNUSED(x) UNUSED_ ## x
5548
#endif
5649

57-
static PyObject *Reader_constructor(PyObject *UNUSED(self), PyObject * args)
50+
static PyObject *Reader_constructor(PyObject *UNUSED(self), PyObject *args)
5851
{
5952
char *filename;
6053

@@ -77,13 +70,15 @@ static PyObject *Reader_constructor(PyObject *UNUSED(self), PyObject * args)
7770

7871
Reader_obj *obj = PyObject_New(Reader_obj, &Reader_Type);
7972
if (!obj) {
73+
PyErr_NoMemory();
8074
return NULL;
8175
}
8276

8377
uint16_t status = MMDB_open(filename, MMDB_MODE_MMAP, mmdb);
8478

8579
if (MMDB_SUCCESS != status) {
8680
free(mmdb);
81+
PyObject_Del(obj);
8782
return PyErr_Format(
8883
MaxMindDB_error,
8984
"Error opening database file (%s). Is this a valid MaxMind DB file?",
@@ -95,7 +90,7 @@ static PyObject *Reader_constructor(PyObject *UNUSED(self), PyObject * args)
9590
return (PyObject *)obj;
9691
}
9792

98-
static PyObject *Reader_get(PyObject * self, PyObject * args)
93+
static PyObject *Reader_get(PyObject *self, PyObject *args)
9994
{
10095
char *ip_address = NULL;
10196

@@ -131,14 +126,11 @@ static PyObject *Reader_get(PyObject * self, PyObject * args)
131126
return NULL;
132127
}
133128

134-
MMDB_entry_data_list_s *entry_data_list = NULL;
135-
136129
if (!result.found_entry) {
137130
Py_RETURN_NONE;
138131
}
139132

140-
PyObject *py_obj = NULL;
141-
133+
MMDB_entry_data_list_s *entry_data_list = NULL;
142134
int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list);
143135
if (MMDB_SUCCESS != status) {
144136
PyErr_Format(MaxMindDB_error,
@@ -154,8 +146,9 @@ static PyObject *Reader_get(PyObject * self, PyObject * args)
154146
return NULL;
155147
}
156148

157-
handle_entry_data_list(entry_data_list, &py_obj);
158-
MMDB_free_entry_data_list(entry_data_list);
149+
MMDB_entry_data_list_s *original_entry_data_list = entry_data_list;
150+
PyObject *py_obj = from_entry_data_list(&entry_data_list);
151+
MMDB_free_entry_data_list(original_entry_data_list);
159152
return py_obj;
160153
}
161154

@@ -174,13 +167,18 @@ static PyObject *Reader_metadata(PyObject *self, PyObject *UNUSED(args))
174167
return NULL;
175168
}
176169

177-
PyObject *metadata_dict;
178-
179170
MMDB_entry_data_list_s *entry_data_list;
180171
MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list);
181-
182-
handle_entry_data_list(entry_data_list, &metadata_dict);
183-
MMDB_free_entry_data_list(entry_data_list);
172+
MMDB_entry_data_list_s *original_entry_data_list = entry_data_list;
173+
174+
PyObject *metadata_dict = from_entry_data_list(&entry_data_list);
175+
MMDB_free_entry_data_list(original_entry_data_list);
176+
if (NULL == metadata_dict || !PyDict_Check(metadata_dict)) {
177+
PyErr_SetString(MaxMindDB_error,
178+
"Error decoding metadata.");
179+
PyObject_Del(obj);
180+
return NULL;
181+
}
184182

185183
obj->binary_format_major_version = PyDict_GetItemString(
186184
metadata_dict, "binary_format_major_version");
@@ -194,6 +192,21 @@ static PyObject *Reader_metadata(PyObject *self, PyObject *UNUSED(args))
194192
obj->node_count = PyDict_GetItemString(metadata_dict, "node_count");
195193
obj->record_size = PyDict_GetItemString(metadata_dict, "record_size");
196194

195+
if (NULL == obj->binary_format_major_version ||
196+
NULL == obj->binary_format_minor_version ||
197+
NULL == obj->build_epoch ||
198+
NULL == obj->database_type ||
199+
NULL == obj->description ||
200+
NULL == obj->ip_version ||
201+
NULL == obj->languages ||
202+
NULL == obj->node_count ||
203+
NULL == obj->record_size) {
204+
PyErr_SetString(MaxMindDB_error,
205+
"Error decoding metadata.");
206+
PyObject_Del(obj);
207+
return NULL;
208+
}
209+
197210
Py_INCREF(obj->binary_format_major_version);
198211
Py_INCREF(obj->binary_format_minor_version);
199212
Py_INCREF(obj->build_epoch);
@@ -203,11 +216,13 @@ static PyObject *Reader_metadata(PyObject *self, PyObject *UNUSED(args))
203216
Py_INCREF(obj->languages);
204217
Py_INCREF(obj->node_count);
205218
Py_INCREF(obj->record_size);
219+
206220
Py_DECREF(metadata_dict);
221+
207222
return (PyObject *)obj;
208223
}
209224

210-
static PyObject *Reader_close(PyObject * self, PyObject *UNUSED(args))
225+
static PyObject *Reader_close(PyObject *self, PyObject *UNUSED(args))
211226
{
212227
Reader_obj *mmdb_obj = (Reader_obj *)self;
213228

@@ -223,7 +238,7 @@ static PyObject *Reader_close(PyObject * self, PyObject *UNUSED(args))
223238
Py_RETURN_NONE;
224239
}
225240

226-
static void Reader_dealloc(PyObject * self)
241+
static void Reader_dealloc(PyObject *self)
227242
{
228243
Reader_obj *obj = (Reader_obj *)self;
229244
if (NULL != obj->mmdb) {
@@ -233,7 +248,7 @@ static void Reader_dealloc(PyObject * self)
233248
PyObject_Del(self);
234249
}
235250

236-
static void Metadata_dealloc(PyObject * self)
251+
static void Metadata_dealloc(PyObject *self)
237252
{
238253
Metadata_obj *obj = (Metadata_obj *)self;
239254
Py_DECREF(obj->binary_format_major_version);
@@ -248,118 +263,108 @@ static void Metadata_dealloc(PyObject * self)
248263
PyObject_Del(self);
249264
}
250265

251-
static const MMDB_entry_data_list_s *handle_entry_data_list(
252-
const MMDB_entry_data_list_s *entry_data_list,
253-
PyObject **py_obj)
266+
static PyObject *from_entry_data_list(MMDB_entry_data_list_s **entry_data_list)
254267
{
255-
switch (entry_data_list->entry_data.type) {
268+
switch ((*entry_data_list)->entry_data.type) {
256269
case MMDB_DATA_TYPE_MAP:
257-
return handle_map(entry_data_list, py_obj);
270+
return from_map(entry_data_list);
258271
case MMDB_DATA_TYPE_ARRAY:
259-
return handle_array(entry_data_list, py_obj);
272+
return from_array(entry_data_list);
260273
case MMDB_DATA_TYPE_UTF8_STRING:
261-
*py_obj = PyUnicode_FromStringAndSize(
262-
entry_data_list->entry_data.utf8_string,
263-
entry_data_list->entry_data.data_size
264-
);
265-
break;
274+
return PyUnicode_FromStringAndSize(
275+
(*entry_data_list)->entry_data.utf8_string,
276+
(*entry_data_list)->entry_data.data_size
277+
);
266278
case MMDB_DATA_TYPE_BYTES:
267-
*py_obj = PyByteArray_FromStringAndSize(
268-
(const char *)entry_data_list->entry_data.bytes,
269-
(Py_ssize_t)entry_data_list->entry_data.data_size);
270-
break;
279+
return PyByteArray_FromStringAndSize(
280+
(const char *)(*entry_data_list)->entry_data.bytes,
281+
(Py_ssize_t)(*entry_data_list)->entry_data.data_size);
271282
case MMDB_DATA_TYPE_DOUBLE:
272-
*py_obj = PyFloat_FromDouble(entry_data_list->entry_data.double_value);
273-
break;
283+
return PyFloat_FromDouble((*entry_data_list)->entry_data.double_value);
274284
case MMDB_DATA_TYPE_FLOAT:
275-
*py_obj = PyFloat_FromDouble(entry_data_list->entry_data.float_value);
276-
break;
285+
return PyFloat_FromDouble((*entry_data_list)->entry_data.float_value);
277286
case MMDB_DATA_TYPE_UINT16:
278-
*py_obj = PyLong_FromLong( entry_data_list->entry_data.uint16);
279-
break;
287+
return PyLong_FromLong( (*entry_data_list)->entry_data.uint16);
280288
case MMDB_DATA_TYPE_UINT32:
281-
*py_obj = PyLong_FromLong(entry_data_list->entry_data.uint32);
282-
break;
289+
return PyLong_FromLong((*entry_data_list)->entry_data.uint32);
283290
case MMDB_DATA_TYPE_BOOLEAN:
284-
*py_obj = PyBool_FromLong(entry_data_list->entry_data.boolean);
285-
break;
291+
return PyBool_FromLong((*entry_data_list)->entry_data.boolean);
286292
case MMDB_DATA_TYPE_UINT64:
287-
*py_obj = PyLong_FromUnsignedLongLong(
288-
entry_data_list->entry_data.uint64);
289-
break;
293+
return PyLong_FromUnsignedLongLong(
294+
(*entry_data_list)->entry_data.uint64);
290295
case MMDB_DATA_TYPE_UINT128:
291-
handle_uint128(entry_data_list, py_obj);
292-
break;
296+
return from_uint128(*entry_data_list);
293297
case MMDB_DATA_TYPE_INT32:
294-
*py_obj = PyLong_FromLong(entry_data_list->entry_data.int32);
295-
break;
298+
return PyLong_FromLong((*entry_data_list)->entry_data.int32);
296299
default:
297300
PyErr_Format(MaxMindDB_error,
298301
"Invalid data type arguments: %d",
299-
entry_data_list->entry_data.type);
302+
(*entry_data_list)->entry_data.type);
300303
return NULL;
301304
}
302-
return entry_data_list->next;
305+
return NULL;
303306
}
304307

305-
static const MMDB_entry_data_list_s *handle_map(
306-
const MMDB_entry_data_list_s *entry_data_list,
307-
PyObject **py_obj)
308+
static PyObject *from_map(MMDB_entry_data_list_s **entry_data_list)
308309
{
309-
*py_obj = PyDict_New();
310-
if (*py_obj == NULL) {
310+
PyObject *py_obj = PyDict_New();
311+
if (NULL == py_obj) {
311312
PyErr_NoMemory();
312313
return NULL;
313314
}
314315

315-
const uint32_t map_size = entry_data_list->entry_data.data_size;
316-
entry_data_list = entry_data_list->next;
316+
const uint32_t map_size = (*entry_data_list)->entry_data.data_size;
317317

318318
uint i;
319319
for (i = 0; i < map_size && entry_data_list; i++) {
320-
PyObject *key, *value;
320+
*entry_data_list = (*entry_data_list)->next;
321321

322-
key = PyUnicode_FromStringAndSize(
323-
(char *)entry_data_list->entry_data.utf8_string,
324-
entry_data_list->entry_data.data_size
322+
PyObject *key = PyUnicode_FromStringAndSize(
323+
(char *)(*entry_data_list)->entry_data.utf8_string,
324+
(*entry_data_list)->entry_data.data_size
325325
);
326326

327-
entry_data_list = entry_data_list->next;
327+
*entry_data_list = (*entry_data_list)->next;
328328

329-
entry_data_list = handle_entry_data_list(entry_data_list,
330-
&value);
331-
PyDict_SetItem(*py_obj, key, value);
329+
PyObject *value = from_entry_data_list(entry_data_list);
330+
if (NULL == value) {
331+
Py_DECREF(key);
332+
Py_DECREF(py_obj);
333+
return NULL;
334+
}
335+
PyDict_SetItem(py_obj, key, value);
332336
Py_DECREF(value);
333337
Py_DECREF(key);
334338
}
335-
return entry_data_list;
339+
340+
return py_obj;
336341
}
337342

338-
static const MMDB_entry_data_list_s *handle_array(
339-
const MMDB_entry_data_list_s *entry_data_list,
340-
PyObject **py_obj)
343+
static PyObject *from_array(MMDB_entry_data_list_s **entry_data_list)
341344
{
342-
const uint32_t size = entry_data_list->entry_data.data_size;
345+
const uint32_t size = (*entry_data_list)->entry_data.data_size;
343346

344-
*py_obj = PyList_New(size);
345-
if (*py_obj == NULL) {
347+
PyObject *py_obj = PyList_New(size);
348+
if (NULL == py_obj) {
346349
PyErr_NoMemory();
347350
return NULL;
348351
}
349-
entry_data_list = entry_data_list->next;
350352

351353
uint i;
352354
for (i = 0; i < size && entry_data_list; i++) {
353-
PyObject *new_value;
354-
entry_data_list = handle_entry_data_list(entry_data_list,
355-
&new_value);
356-
PyList_SET_ITEM(*py_obj, i, new_value);
355+
*entry_data_list = (*entry_data_list)->next;
356+
PyObject *value = from_entry_data_list(entry_data_list);
357+
if (NULL == value) {
358+
Py_DECREF(py_obj);
359+
return NULL;
360+
}
361+
// PyList_SetItem 'steals' the reference
362+
PyList_SetItem(py_obj, i, value);
357363
}
358-
return entry_data_list;
364+
return py_obj;
359365
}
360366

361-
static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
362-
PyObject **py_obj)
367+
static PyObject *from_uint128(const MMDB_entry_data_list_s *entry_data_list)
363368
{
364369
uint64_t high = 0;
365370
uint64_t low = 0;
@@ -377,18 +382,18 @@ static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
377382
low = (uint64_t)entry_data_list->entry_data.uint128;
378383
#endif
379384

380-
char *num_str;
381-
int status = asprintf(&num_str, "%016" PRIX64 "%016" PRIX64, high, low);
382-
383-
if (status == -1) {
385+
char *num_str = malloc(33);
386+
if (NULL == num_str) {
384387
PyErr_NoMemory();
385-
*py_obj = NULL;
386-
return;
388+
return NULL;
387389
}
388390

389-
*py_obj = PyLong_FromString(num_str, NULL, 16);
391+
snprintf(num_str, 33, "%016" PRIX64 "%016" PRIX64, high, low);
392+
393+
PyObject *py_obj = PyLong_FromString(num_str, NULL, 16);
390394

391395
free(num_str);
396+
return py_obj;
392397
}
393398

394399
static PyMethodDef Reader_methods[] = {

setup.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
# This import is apparently needed for Nose on Red Hat's Python
12
import multiprocessing
3+
24
try:
35
from setuptools import setup, Extension
46
except ImportError:
@@ -9,7 +11,8 @@
911
'maxminddb',
1012
libraries=['maxminddb'],
1113
sources=['maxminddb.c'],
12-
extra_compile_args=['-Wall', '-Werror', '-Wextra'],
14+
extra_compile_args=[
15+
'-Wall', '-Werror', '-Wextra', '-std=c99', '-pedantic'],
1316
)
1417

1518
setup(

0 commit comments

Comments
 (0)