Skip to content

Commit b9da662

Browse files
authored
BUG: fix memory leak in JSON datetime serialization (#62217)
1 parent aabbbc5 commit b9da662

File tree

1 file changed

+38
-10
lines changed

1 file changed

+38
-10
lines changed

pandas/_libs/src/vendored/ujson/python/objToJSON.c

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ Numeric decoder derived from TCL library
5151
#include <numpy/ndarraytypes.h>
5252
#include <numpy/npy_math.h>
5353

54+
static const int CSTR_SIZE = 20;
55+
5456
npy_int64 get_nat(void) { return NPY_MIN_INT64; }
5557

5658
typedef const char *(*PFN_PyTypeToUTF8)(JSOBJ obj, JSONTypeContext *ti,
@@ -106,7 +108,7 @@ typedef struct __TypeContext {
106108
double doubleValue;
107109
JSINT64 longValue;
108110

109-
const char *cStr;
111+
char *cStr;
110112
NpyArrContext *npyarr;
111113
PdBlockContext *pdblock;
112114
int transpose;
@@ -347,7 +349,8 @@ static const char *PyDateTimeToIsoCallback(JSOBJ obj, JSONTypeContext *tc,
347349
}
348350

349351
NPY_DATETIMEUNIT base = ((PyObjectEncoder *)tc->encoder)->datetimeUnit;
350-
return PyDateTimeToIso(obj, base, len);
352+
GET_TC(tc)->cStr = PyDateTimeToIso(obj, base, len);
353+
return GET_TC(tc)->cStr;
351354
}
352355

353356
static const char *PyTimeToJSON(JSOBJ _obj, JSONTypeContext *tc,
@@ -1007,16 +1010,24 @@ static const char *List_iterGetName(JSOBJ Py_UNUSED(obj),
10071010
//=============================================================================
10081011
static void Index_iterBegin(JSOBJ Py_UNUSED(obj), JSONTypeContext *tc) {
10091012
GET_TC(tc)->index = 0;
1013+
GET_TC(tc)->cStr = PyObject_Malloc(CSTR_SIZE);
1014+
if (!GET_TC(tc)->cStr) {
1015+
PyErr_NoMemory();
1016+
}
10101017
}
10111018

10121019
static int Index_iterNext(JSOBJ obj, JSONTypeContext *tc) {
10131020
const Py_ssize_t index = GET_TC(tc)->index;
10141021
Py_XDECREF(GET_TC(tc)->itemValue);
1022+
if (!GET_TC(tc)->cStr) {
1023+
return 0;
1024+
}
1025+
10151026
if (index == 0) {
1016-
GET_TC(tc)->cStr = "name";
1027+
strcpy(GET_TC(tc)->cStr, "name");
10171028
GET_TC(tc)->itemValue = PyObject_GetAttrString(obj, "name");
10181029
} else if (index == 1) {
1019-
GET_TC(tc)->cStr = "data";
1030+
strcpy(GET_TC(tc)->cStr, "data");
10201031
GET_TC(tc)->itemValue = get_values(obj);
10211032
if (!GET_TC(tc)->itemValue) {
10221033
return 0;
@@ -1049,19 +1060,27 @@ static void Series_iterBegin(JSOBJ Py_UNUSED(obj), JSONTypeContext *tc) {
10491060
PyObjectEncoder *enc = (PyObjectEncoder *)tc->encoder;
10501061
GET_TC(tc)->index = 0;
10511062
enc->outputFormat = VALUES; // for contained series
1063+
GET_TC(tc)->cStr = PyObject_Malloc(CSTR_SIZE);
1064+
if (!GET_TC(tc)->cStr) {
1065+
PyErr_NoMemory();
1066+
}
10521067
}
10531068

10541069
static int Series_iterNext(JSOBJ obj, JSONTypeContext *tc) {
10551070
const Py_ssize_t index = GET_TC(tc)->index;
10561071
Py_XDECREF(GET_TC(tc)->itemValue);
1072+
if (!GET_TC(tc)->cStr) {
1073+
return 0;
1074+
}
1075+
10571076
if (index == 0) {
1058-
GET_TC(tc)->cStr = "name";
1077+
strcpy(GET_TC(tc)->cStr, "name");
10591078
GET_TC(tc)->itemValue = PyObject_GetAttrString(obj, "name");
10601079
} else if (index == 1) {
1061-
GET_TC(tc)->cStr = "index";
1080+
strcpy(GET_TC(tc)->cStr, "index");
10621081
GET_TC(tc)->itemValue = PyObject_GetAttrString(obj, "index");
10631082
} else if (index == 2) {
1064-
GET_TC(tc)->cStr = "data";
1083+
strcpy(GET_TC(tc)->cStr, "data");
10651084
GET_TC(tc)->itemValue = get_values(obj);
10661085
if (!GET_TC(tc)->itemValue) {
10671086
return 0;
@@ -1096,19 +1115,27 @@ static void DataFrame_iterBegin(JSOBJ Py_UNUSED(obj), JSONTypeContext *tc) {
10961115
PyObjectEncoder *enc = (PyObjectEncoder *)tc->encoder;
10971116
GET_TC(tc)->index = 0;
10981117
enc->outputFormat = VALUES; // for contained series & index
1118+
GET_TC(tc)->cStr = PyObject_Malloc(CSTR_SIZE);
1119+
if (!GET_TC(tc)->cStr) {
1120+
PyErr_NoMemory();
1121+
}
10991122
}
11001123

11011124
static int DataFrame_iterNext(JSOBJ obj, JSONTypeContext *tc) {
11021125
const Py_ssize_t index = GET_TC(tc)->index;
11031126
Py_XDECREF(GET_TC(tc)->itemValue);
1127+
if (!GET_TC(tc)->cStr) {
1128+
return 0;
1129+
}
1130+
11041131
if (index == 0) {
1105-
GET_TC(tc)->cStr = "columns";
1132+
strcpy(GET_TC(tc)->cStr, "columns");
11061133
GET_TC(tc)->itemValue = PyObject_GetAttrString(obj, "columns");
11071134
} else if (index == 1) {
1108-
GET_TC(tc)->cStr = "index";
1135+
strcpy(GET_TC(tc)->cStr, "index");
11091136
GET_TC(tc)->itemValue = PyObject_GetAttrString(obj, "index");
11101137
} else if (index == 2) {
1111-
GET_TC(tc)->cStr = "data";
1138+
strcpy(GET_TC(tc)->cStr, "data");
11121139
Py_INCREF(obj);
11131140
GET_TC(tc)->itemValue = obj;
11141141
} else {
@@ -1880,6 +1907,7 @@ static void Object_endTypeContext(JSOBJ Py_UNUSED(obj), JSONTypeContext *tc) {
18801907
GET_TC(tc)->rowLabels = NULL;
18811908
NpyArr_freeLabels(GET_TC(tc)->columnLabels, GET_TC(tc)->columnLabelsLen);
18821909
GET_TC(tc)->columnLabels = NULL;
1910+
PyObject_Free(GET_TC(tc)->cStr);
18831911
GET_TC(tc)->cStr = NULL;
18841912
PyObject_Free(tc->prv);
18851913
tc->prv = NULL;

0 commit comments

Comments
 (0)