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 }