File: rrdtoolmodule.c
Function: _rrdtool_fetch_cb_wrapper
Error: memory leak: ob_refcnt of '*tmp_min_ts' is 1 too high
1058 static int
1059 _rrdtool_fetch_cb_wrapper(
1060     const char *filename,
1061     enum cf_en cf_idx,
1062     time_t *start,
1063     time_t *end,
1064     unsigned long *step,
1065     unsigned long *ds_cnt,
1066     char ***ds_namv,
1067     rrd_value_t **data)
1068 {
1069     PyObject *args;
1070     PyObject *kwargs;
1071     PyObject *ret = NULL;
1072     PyObject *tmp;
1073     PyObject *tmp_min_ts;
1074     PyGILState_STATE gstate;
1075     Py_ssize_t rowcount = 0;
1076     int rc = -1;
1077     unsigned int i, ii;
1078 
1079     gstate = PyGILState_Ensure();
PyGILState_Ensure
1080 
1081     if (_rrdtool_fetch_callable == NULL) {
when treating unknown struct PyObject * from rrdtoolmodule.c:1056 as non-NULL
taking False path
1082         rrd_set_error("use rrdtool.register_fetch_cb to register a fetch callback");
1083         goto gil_release_err;
1084     }
1085 
1086     args = PyTuple_New(0);
when PyTuple_New() succeeds
1087     kwargs = PyDict_New();
when PyDict_New() succeeds
1088 
1089     /* minimum possible UNIX datetime */
1090     tmp_min_ts = PyLong_FromLong(0);
when PyLong_FromLong() succeeds
'*tmp_min_ts' was allocated at:     tmp_min_ts = PyLong_FromLong(0);
ob_refcnt is now refs: 1 owned
1091 
1092     PyObject *po_filename = PyRRD_String_FromString(filename);
when PyUnicode_FromString() succeeds
1093     PyDict_SetItemString(kwargs, "filename", po_filename);
when PyDict_SetItemString() succeeds
1094     Py_DECREF(po_filename);
taking False path
1095 
1096     PyObject *po_cfstr = PyRRD_String_FromString(PyRRD_String_FromCF(cf_idx));
when PyUnicode_FromString() succeeds
1097     PyDict_SetItemString(kwargs, "cf", po_cfstr);
when PyDict_SetItemString() succeeds
1098     Py_DECREF(po_cfstr);
taking False path
1099 
1100     PyObject *po_start = PyLong_FromLong(*start);
when treating unknown time_t * from rrdtoolmodule.c:1062 as non-NULL
when PyLong_FromLong() succeeds
1101     PyDict_SetItemString(kwargs, "start", po_start);
when PyDict_SetItemString() succeeds
1102     Py_DECREF(po_start);
taking False path
1103 
1104     PyObject *po_end = PyLong_FromLong(*end);
when treating unknown time_t * from rrdtoolmodule.c:1063 as non-NULL
when PyLong_FromLong() succeeds
1105     PyDict_SetItemString(kwargs, "end", po_end);
when PyDict_SetItemString() succeeds
1106     Py_DECREF(po_end);
taking False path
1107 
1108     PyObject *po_step = PyLong_FromUnsignedLong(*step);
when treating unknown long unsigned int * from rrdtoolmodule.c:1064 as non-NULL
when PyLong_FromUnsignedLong() succeeds
1109     PyDict_SetItemString(kwargs, "step", po_step);
when PyDict_SetItemString() succeeds
1110     Py_DECREF(po_step);
taking False path
1111 
1112     /* execute Python callback method */
1113     ret = PyObject_Call(_rrdtool_fetch_callable, args, kwargs);
when PyObject_Call() succeeds
1114     Py_DECREF(args);
when taking True path
1115     Py_DECREF(kwargs);
when taking True path
1116 
1117     if (ret == NULL) {
taking False path
1118         rrd_set_error("calling python callback failed");
1119         goto gil_release_err;
1120     }
1121 
1122     /* handle return value of callback */
1123     if (!PyDict_Check(ret)) {
when considering range: 1 <= value <= 0x20000000
taking False path
1124         rrd_set_error("expected callback method to be a dict");
1125         goto gil_release_err;
1126     }
1127 
1128     tmp = PyDict_GetItemString(ret, "step");
when PyDict_GetItemString() succeeds
1129     if (tmp == NULL) {
taking False path
1130         rrd_set_error("expected 'step' key in callback return value");
1131         goto gil_release_err;
1132     } else if (!PyRRD_Long_Check(tmp)) {
when considering range: 1 <= value <= 0x1000000
taking False path
1133         rrd_set_error("the 'step' key in callback return value must be int");
1134         goto gil_release_err;
1135     } else
1136         *step = PyLong_AsLong(tmp);
1137 
1138     tmp = PyDict_GetItemString(ret, "start");
when PyDict_GetItemString() succeeds
1139     if (tmp == NULL) {
taking False path
1140         rrd_set_error("expected 'start' key in callback return value");
1141         goto gil_release_err;
1142     } else if (!PyRRD_Long_Check(tmp)) {
when considering range: 1 <= value <= 0x1000000
taking False path
1143         rrd_set_error("expected 'start' key in callback return value to be "
1144             "of type int");
1145         goto gil_release_err;
1146     } else if (PyObject_RichCompareBool(tmp, tmp_min_ts, Py_EQ) ||
when considering value == (int)0 from rrdtoolmodule.c:1146
taking False path
when considering value == (int)0 from rrdtoolmodule.c:1147
taking False path
1147                PyObject_RichCompareBool(tmp, po_start, Py_LT)) {
1148         rrd_set_error("expected 'start' value in callback return dict to be "
1149             "equal or earlier than passed start timestamp");
1150         goto gil_release_err;
1151     } else {
1152         *start = PyLong_AsLong(po_start);
1153 
1154         if (*start == -1) {
when considering range: -0x8000000000000000 <= value <= -2
taking False path
1155             rrd_set_error("expected 'start' value in callback return value to"
1156                 " not exceed LONG_MAX");
1157             goto gil_release_err;
1158         }
1159     }
1160 
1161     tmp = PyDict_GetItemString(ret, "data");
when PyDict_GetItemString() succeeds
1162     if (tmp == NULL) {
taking False path
1163         rrd_set_error("expected 'data' key in callback return value");
1164         goto gil_release_err;
1165     } else if (!PyDict_Check(tmp)) {
when considering value == (long unsigned int)0 from rrdtoolmodule.c:1165
taking True path
1166         rrd_set_error("expected 'data' key in callback return value of type "
1167             "dict");
1168         goto gil_release_err;
1169     } else {
1170         *ds_cnt = (unsigned long)PyDict_Size(tmp);
1171         *ds_namv = (char **)calloc(*ds_cnt, sizeof(char *));
1172 
1173         if (*ds_namv == NULL) {
1174             rrd_set_error("an error occurred while allocating memory for "
1175                 "ds_namv when allocating memory for python callback");
1176             goto gil_release_err;
1177         }
1178 
1179         PyObject *key, *value;
1180         Py_ssize_t pos = 0;  /* don't use pos for indexing */
1181         unsigned int x = 0;
1182 
1183         while (PyDict_Next(tmp, &pos, &key, &value)) {
1184             const char *key_str = PyRRD_String_AS_STRING(key);
1185 
1186             if (key_str == NULL) {
1187                 rrd_set_error("key of 'data' element from callback return "
1188                     "value is not a string");
1189                 goto gil_release_free_dsnamv_err;
1190             } else if (strlen(key_str) > DS_NAM_SIZE) {
1191                 rrd_set_error("key '%s' longer than the allowed maximum of %d "
1192                     "byte", key_str, DS_NAM_SIZE - 1);
1193                 goto gil_release_free_dsnamv_err;
1194             }
1195 
1196             if ((((*ds_namv)[x]) = (char *)malloc(sizeof(char) * DS_NAM_SIZE)) == NULL) {
1197                 rrd_set_error("malloc fetch ds_namv entry");
1198                 goto gil_release_free_dsnamv_err;
1199             }
1200 
1201             strncpy((*ds_namv)[x], key_str, DS_NAM_SIZE - 1);
1202             (*ds_namv)[x][DS_NAM_SIZE - 1] = '\0';
1203 
1204             if (!PyList_Check(value)) {
1205                 rrd_set_error("expected 'data' dict values in callback return "
1206                     "value of type list");
1207                 goto gil_release_free_dsnamv_err;
1208             } else if (PyList_Size(value) > rowcount)
1209                 rowcount = PyList_Size(value);
1210 
1211             ++x;
1212         }
1213 
1214         *end = *start + *step * rowcount;
1215 
1216         if (((*data) = (rrd_value_t *)malloc(*ds_cnt * rowcount * sizeof(rrd_value_t))) == NULL) {
1217             rrd_set_error("malloc fetch data area");
1218             goto gil_release_free_dsnamv_err;
1219         }
1220 
1221         for (i = 0; i < *ds_cnt; i++) {
1222             for (ii = 0; ii < (unsigned int)rowcount; ii++) {
1223                 char *ds_namv_i = (*ds_namv)[i];
1224                 double va;
1225                 PyObject *lstv = PyList_GetItem(PyDict_GetItemString(tmp, ds_namv_i), ii);
1226 
1227                 /* lstv may be NULL here in case an IndexError has been raised;
1228                    in such case the rowcount is higher than the number of elements for
1229                    the list of that ds. use DNAN as value for these then */
1230                 if (lstv == NULL || lstv == Py_None) {
1231                     if (lstv == NULL)
1232                         PyErr_Clear();
1233                     va = DNAN;
1234                 }
1235                 else {
1236                     va = PyFloat_AsDouble(lstv);
1237                     if (va == -1.0 && PyErr_Occurred()) {
1238                         PyObject *exc_type, *exc_value, *exc_value_str = NULL, *exc_tb;
1239                         PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
1240 
1241                         if (exc_value != NULL) {
1242                             exc_value_str = PyObject_Str(exc_value);
1243                             rrd_set_error((char *)PyRRD_String_AS_STRING(exc_value_str));
1244                             Py_DECREF(exc_value);
1245                         }
1246 
1247                         Py_DECREF(exc_type);
1248                         Py_DECREF(exc_value_str);
1249                         if (exc_tb != NULL)
1250                             Py_DECREF(exc_tb);
1251                         goto gil_release_free_dsnamv_err;
1252                     }
1253                 }
1254 
1255                 (*data)[i + ii * (*ds_cnt)] = va;
1256             }
1257         }
1258     }
1259 
1260     /* success */
1261     rc = 1;
1262     goto gil_release;
1263 
1264 gil_release_free_dsnamv_err:
1265     for (i = 0; i < *ds_cnt; i++) {
1266         if ((*ds_namv)[i]) {
1267             free((*ds_namv)[i]);
1268         }
1269     }
1270 
1271     free(*ds_namv);
1272 
1273 gil_release_err:
1274     rc = -1;
1275 
1276 gil_release:
1277     if (ret != NULL)
taking True path
1278         Py_DECREF(ret);
when taking True path
1279     PyGILState_Release(gstate);
calling PyGILState_Release()
1280     return rc;
returning
memory leak: ob_refcnt of '*tmp_min_ts' is 1 too high
was expecting final owned ob_refcnt of '*tmp_min_ts' to be 0 since nothing references it but final ob_refcnt is refs: 1 owned
found 11 similar trace(s) to this
1281 }