Bug Summary

File:build-analysis/../src/xmms/medialib_query_result.c
Warning:line 321, column 12
Function call argument is an uninitialized value

Annotated Source Code

1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2003-2017 XMMS2 Team
3 *
4 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 */
16
17#include <xmmspriv/xmms_fetch_info.h>
18#include <xmmspriv/xmms_fetch_spec.h>
19#include "s4.h"
20
21#include <glib.h>
22#include <glib/gstdio.h>
23
24xmmsv_t *xmms_medialib_query_to_xmmsv (s4_resultset_t *set, xmms_fetch_spec_t *spec);
25
26typedef struct {
27 gint64 sum;
28 gint n;
29} avg_data_t;
30
31typedef struct {
32 xmmsv_t *data;
33 gint n;
34} random_data_t;
35
36typedef struct {
37 GHashTable *ht;
38 xmmsv_t *list;
39} set_data_t;
40
41static xmmsv_t *
42aggregate_first (xmmsv_t *current, gint int_value, const gchar *str_value)
43{
44 if (current != NULL((void*)0)) {
45 return current;
46 }
47
48 if (str_value != NULL((void*)0)) {
49 current = xmmsv_new_string (str_value);
50 } else {
51 current = xmmsv_new_int (int_value);
52 }
53
54 return current;
55}
56
57static xmmsv_t *
58aggregate_list (xmmsv_t *current, gint int_value, const gchar *str_value)
59{
60 if (current == NULL((void*)0)) {
61 current = xmmsv_new_list ();
62 }
63
64 if (str_value != NULL((void*)0)) {
65 xmmsv_list_append_string (current, str_value);
66 } else {
67 xmmsv_list_append_int (current, int_value);
68 }
69
70 return current;
71}
72
73static xmmsv_t *
74aggregate_set (xmmsv_t *current, gint int_value, const gchar *str_value)
75{
76 set_data_t *data;
77 xmmsv_t *value;
78 gpointer key;
79 guint length;
80
81 if (current == NULL((void*)0)) {
82 set_data_t init = {
83 .ht = g_hash_table_new (NULL((void*)0), NULL((void*)0)),
84 .list = xmmsv_new_list ()
85 };
86 current = xmmsv_new_bin ((guchar *) &init, sizeof (set_data_t));
87 }
88
89 xmmsv_get_bin (current, (const guchar **) &data, &length);
90
91 if (str_value != NULL((void*)0)) {
92 value = xmmsv_new_string (str_value);
93 key = (gpointer) str_value;
94 } else {
95 value = xmmsv_new_int (int_value);
96 key = GINT_TO_POINTER (int_value)((gpointer) (glong) (int_value));
97 }
98
99 if (g_hash_table_lookup (data->ht, key) == NULL((void*)0)) {
100 g_hash_table_insert (data->ht, key, value);
101 xmmsv_list_append (data->list, value);
102 }
103
104 xmmsv_unref (value);
105
106 return current;
107}
108
109static xmmsv_t *
110aggregate_sum (xmmsv_t *current, gint int_value, const gchar *str_value)
111{
112 int64_t old_value = 0;
113
114 if (str_value != NULL((void*)0)) {
115 /* 'sum' only applies to numbers */
116 return current;
117 }
118
119 if (current != NULL((void*)0)) {
120 xmmsv_get_int64 (current, &old_value);
121 }
122
123 return xmmsv_new_int (old_value + int_value);
124}
125
126static xmmsv_t *
127aggregate_min (xmmsv_t *current, gint int_value, const gchar *str_value)
128{
129 gint old_value;
130
131 if (str_value != NULL((void*)0)) {
132 /* 'min' only applies to numbers */
133 return current;
134 }
135
136 if (current == NULL((void*)0)) {
137 return xmmsv_new_int (int_value);
138 }
139
140 xmmsv_get_intxmmsv_get_int32 (current, &old_value);
141
142 if (old_value > int_value) {
143 return xmmsv_new_int (int_value);
144 }
145
146 return current;
147}
148
149static xmmsv_t *
150aggregate_max (xmmsv_t *current, gint int_value, const gchar *str_value)
151{
152 gint old_value;
153
154 if (str_value != NULL((void*)0)) {
155 /* 'max' only applies to numbers */
156 return current;
157 }
158
159 if (current == NULL((void*)0)) {
160 return xmmsv_new_int (int_value);
161 }
162
163 xmmsv_get_intxmmsv_get_int32 (current, &old_value);
164
165 if (old_value < int_value) {
166 return xmmsv_new_int (int_value);
167 }
168
169 return current;
170}
171
172static xmmsv_t *
173aggregate_random (xmmsv_t *current, gint int_value, const gchar *str_value)
174{
175 random_data_t *data;
176 guint length;
177
178 if (current == NULL((void*)0)) {
179 random_data_t init = { 0 };
180 current = xmmsv_new_bin ((guchar *) &init, sizeof (random_data_t));
181 }
182
183 xmmsv_get_bin (current, (const guchar **) &data, &length);
184
185 data->n++;
186
187 if (g_random_int_range (0, data->n) == 0) {
188 if (data->data != NULL((void*)0)) {
189 xmmsv_unref (data->data);
190 }
191
192 if (str_value != NULL((void*)0)) {
193 data->data = xmmsv_new_string (str_value);
194 } else {
195 data->data = xmmsv_new_int (int_value);
196 }
197 }
198
199 return current;
200}
201
202static xmmsv_t *
203aggregate_average (xmmsv_t *current, gint int_value, const gchar *str_value)
204{
205 avg_data_t *data;
206 guint length;
207
208 if (current == NULL((void*)0)) {
209 avg_data_t init = { 0 };
210 current = xmmsv_new_bin ((guchar *) &init, sizeof (avg_data_t));
211 }
212
213 xmmsv_get_bin (current, (const guchar **) &data, &length);
214
215 if (str_value == NULL((void*)0)) {
216 data->n++;
217 data->sum += int_value;
218 }
219
220 return current;
221}
222
223/* Converts an S4 result (a column) into an xmmsv values */
224static void *
225result_to_xmmsv (xmmsv_t *ret, gint32 id, const s4_result_t *res,
226 xmms_fetch_spec_t *spec)
227{
228 static xmmsv_t * (*aggregate_functions[AGGREGATE_END])(xmmsv_t *c, gint i, const gchar *s) = {
229 aggregate_first,
230 aggregate_sum,
231 aggregate_max,
232 aggregate_min,
233 aggregate_set,
234 aggregate_list,
235 aggregate_random,
236 aggregate_average
237 };
238 const s4_val_t *val;
239 xmmsv_t *dict, *current;
240 const gchar *str_value, *key = NULL((void*)0);
241 gint32 i, int_value;
1
'int_value' declared without an initial value
242 xmmsv_t *newval;
243
244 g_return_val_if_fail (spec->data.metadata.get_size > 0, ret)do{ if (spec->data.metadata.get_size > 0) { } else { g_return_if_fail_warning
("core", ((const char*) (__func__)), "spec->data.metadata.get_size > 0"
); return (ret); }; }while (0)
;
245 g_return_val_if_fail (spec->data.metadata.get_size <= METADATA_END, ret)do{ if (spec->data.metadata.get_size <= METADATA_END) {
} else { g_return_if_fail_warning ("core", ((const char*) (__func__
)), "spec->data.metadata.get_size <= METADATA_END"); return
(ret); }; }while (0)
;
246 g_return_val_if_fail (spec->data.metadata.aggr_func >= 0, ret)do{ if (spec->data.metadata.aggr_func >= 0) { } else { g_return_if_fail_warning
("core", ((const char*) (__func__)), "spec->data.metadata.aggr_func >= 0"
); return (ret); }; }while (0)
;
247 g_return_val_if_fail (spec->data.metadata.aggr_func < AGGREGATE_END, ret)do{ if (spec->data.metadata.aggr_func < AGGREGATE_END) {
} else { g_return_if_fail_warning ("core", ((const char*) (__func__
)), "spec->data.metadata.aggr_func < AGGREGATE_END"); return
(ret); }; }while (0)
;
248
249 /* Loop through all the values the column has */
250 while (res != NULL((void*)0)) {
2
Assuming 'res' is not equal to NULL
3
Loop condition is true. Entering loop body
251 dict = ret;
252 current = ret;
253
254 /* Loop through the list of what to get ("key", "source", ..) */
255 for (i = 0; i < spec->data.metadata.get_size; i++) {
4
Loop condition is false. Execution continues on line 321
256 str_value = NULL((void*)0);
257 int_value = 0;
258
259 /* Fill str_value with the correct value if it is a string
260 * or int_value if it is an integer
261 */
262 switch (spec->data.metadata.get[i]) {
263 case METADATA_KEY:
264 str_value = s4_result_get_key (res);
265 break;
266 case METADATA_SOURCE:
267 str_value = s4_result_get_src (res);
268 if (str_value == NULL((void*)0))
269 str_value = "server";
270 break;
271 case METADATA_ID:
272 int_value = id;
273 break;
274 case METADATA_VALUE:
275 val = s4_result_get_val (res);
276
277 if (!s4_val_get_int (val, &int_value)) {
278 s4_val_get_str (val, &str_value);
279 }
280 break;
281 default:
282 g_assert_not_reached ()do { g_assertion_message_expr ("core", "../src/xmms/medialib_query_result.c"
, 282, ((const char*) (__func__)), ((void*)0)); } while (0)
;
283 }
284
285 /* If this is not the last property to get we use this property
286 * as a key in a dict
287 */
288 if (i < (spec->data.metadata.get_size - 1)) {
289 /* Convert integers to strings */
290 if (str_value == NULL((void*)0)) {
291 /* Big enough to hold 2^32 with minus sign */
292 gchar buf[12];
293 g_sprintf (buf, "%i", int_value);
294 key = buf;
295 } else {
296 key = str_value;
297 }
298
299 /* Make sure the root dict exists */
300 if (dict == NULL((void*)0)) {
301 ret = dict = xmmsv_new_dict ();
302 }
303
304 /* If this dict contains dicts we have to create a new
305 * dict if one does not exists for the key yet
306 */
307 if (!xmmsv_dict_get (dict, key, &current))
308 current = NULL((void*)0);
309
310 if (i < (spec->data.metadata.get_size - 2)) {
311 if (current == NULL((void*)0)) {
312 current = xmmsv_new_dict ();
313 xmmsv_dict_set (dict, key, current);
314 xmmsv_unref (current);
315 }
316 dict = current;
317 }
318 }
319 }
320
321 newval = aggregate_functions[spec->data.metadata.aggr_func](current, int_value, str_value);
5
Function call argument is an uninitialized value
322
323 /* Update the previous dict (if there is one) */
324 if (newval != current) {
325 if (i > 1) {
326 xmmsv_dict_set (dict, key, newval);
327 xmmsv_unref (newval);
328 } else {
329 ret = newval;
330 if (current != NULL((void*)0)) {
331 xmmsv_unref (current);
332 }
333 }
334 }
335
336 res = s4_result_next (res);
337 }
338
339 return ret;
340}
341
342/* Converts the temporary value returned by result_to_xmmsv into the real value */
343static xmmsv_t *
344aggregate_data (xmmsv_t *value, aggregate_function_t aggr_func)
345{
346 const random_data_t *random_data;
347 const avg_data_t *avg_data;
348 const set_data_t *set_data;
349 gconstpointer data;
350 xmmsv_t *ret;
351 guint len;
352
353 ret = NULL((void*)0);
354 data = NULL((void*)0);
355
356 if (value != NULL((void*)0) && xmmsv_is_type (value, XMMSV_TYPE_BIN))
357 xmmsv_get_bin (value, (const guchar **) &data, &len);
358
359 switch (aggr_func) {
360 case AGGREGATE_FIRST:
361 case AGGREGATE_MIN:
362 case AGGREGATE_MAX:
363 case AGGREGATE_SUM:
364 if (value != NULL((void*)0)) {
365 ret = xmmsv_ref (value);
366 } else {
367 ret = xmmsv_new_none ();
368 }
369 break;
370 case AGGREGATE_LIST:
371 if (value != NULL((void*)0)) {
372 ret = xmmsv_ref (value);
373 } else {
374 ret = xmmsv_new_list ();
375 }
376 break;
377 case AGGREGATE_RANDOM:
378 random_data = data;
379 if (random_data != NULL((void*)0)) {
380 ret = random_data->data;
381 } else {
382 ret = xmmsv_new_none ();
383 }
384 break;
385 case AGGREGATE_SET:
386 set_data = data;
387 if (set_data != NULL((void*)0)) {
388 g_hash_table_destroy (set_data->ht);
389 ret = set_data->list;
390 } else {
391 ret = xmmsv_new_list ();
392 }
393 break;
394 case AGGREGATE_AVG:
395 avg_data = data;
396 if (avg_data != NULL((void*)0)) {
397 ret = xmmsv_new_float (avg_data->n ? avg_data->sum * 1.0 / avg_data->n : 0);
398 } else {
399 ret = xmmsv_new_none ();
400 }
401 break;
402 default:
403 g_assert_not_reached ()do { g_assertion_message_expr ("core", "../src/xmms/medialib_query_result.c"
, 403, ((const char*) (__func__)), ((void*)0)); } while (0)
;
404 }
405
406 if (value != NULL((void*)0)) {
407 xmmsv_unref (value);
408 }
409
410 return ret;
411}
412
413/* Applies an aggregation function to the leafs in an xmmsv dict tree */
414static xmmsv_t *
415aggregate_result (xmmsv_t *val, gint depth, aggregate_function_t aggr_func)
416{
417 xmmsv_dict_iter_t *it;
418
419 if (depth == 0) {
420 return aggregate_data (val, aggr_func);
421 }
422
423 if (val == NULL((void*)0) && depth > 0) {
424 return xmmsv_new_dict();
425 }
426
427 /* If it's a dict we call this function recursively on all its values */
428 xmmsv_get_dict_iter (val, &it);
429
430 while (xmmsv_dict_iter_valid (it)) {
431 xmmsv_t *entry;
432
433 xmmsv_dict_iter_pair (it, NULL((void*)0), &entry);
434 xmmsv_ref (entry);
435
436 entry = aggregate_result (entry, depth - 1, aggr_func);
437 xmmsv_dict_iter_set (it, entry);
438 xmmsv_unref (entry);
439
440 xmmsv_dict_iter_next (it);
441 }
442
443 return val;
444}
445
446/* Converts an S4 resultset to an xmmsv using the fetch specification */
447static xmmsv_t *
448metadata_to_xmmsv (s4_resultset_t *set, xmms_fetch_spec_t *spec)
449{
450 const s4_resultrow_t *row;
451 xmmsv_t *ret = NULL((void*)0);
452 gint i;
453
454 /* Loop over the rows in the resultset */
455 for (i = 0; s4_resultset_get_row (set, i, &row); i++) {
456 gint32 id, j;
457
458 s4_val_get_int (s4_result_get_val (s4_resultset_get_result (set, i, 0)), &id);
459 for (j = 0; j < spec->data.metadata.col_count; j++) {
460 const s4_result_t *res;
461
462 if (s4_resultrow_get_col (row, spec->data.metadata.cols[j], &res)) {
463 ret = result_to_xmmsv (ret, id, res, spec);
464 }
465 }
466 }
467
468 return aggregate_result (ret, spec->data.metadata.get_size - 1,
469 spec->data.metadata.aggr_func);
470}
471
472
473/* Divides an S4 set into a list of smaller sets with
474 * the same values for the cluster attributes
475 */
476static void
477cluster_set (s4_resultset_t *set, xmms_fetch_spec_t *spec,
478 GHashTable *table, GList **list)
479{
480 const s4_resultrow_t *row;
481 gint position;
482
483 /* Run through all the rows in the result set.
484 * Uses a hash table to find the correct cluster to put the row in
485 */
486 for (position = 0; s4_resultset_get_row (set, position, &row); position++) {
487 s4_resultset_t *cluster;
488 const s4_result_t *res;
489 const gchar *value = spec->data.cluster.fallback;
490 gchar buf[12];
491
492 if (spec->data.cluster.type == CLUSTER_BY_POSITION) {
493 g_snprintf (buf, sizeof (buf), "%i", position);
494 value = buf;
495 } else if (s4_resultrow_get_col (row, spec->data.cluster.column, &res)) {
496 const s4_val_t *val = s4_result_get_val (res);
497 if (!s4_val_get_str (val, &value)) {
498 gint32 ival;
499 s4_val_get_int (val, &ival);
500 g_snprintf (buf, sizeof (buf), "%i", ival);
501 value = buf;
502 }
503 }
504
505 if (value == NULL((void*)0)) {
506 /* value not found, and no fallback provided */
507 continue;
508 }
509
510 cluster = g_hash_table_lookup (table, value);
511 if (cluster == NULL((void*)0)) {
512 cluster = s4_resultset_create (s4_resultset_get_colcount (set));
513 g_hash_table_insert (table, g_strdup (value), cluster);
514 *list = g_list_prepend (*list, cluster);
515 }
516 s4_resultset_add_row (cluster, row);
517 }
518}
519
520static GList *
521cluster_list (s4_resultset_t *set, xmms_fetch_spec_t *spec)
522{
523 GHashTable *table;
524 GList *list = NULL((void*)0);
525
526 table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
527 cluster_set (set, spec, table, &list);
528 g_hash_table_destroy (table);
529
530 return g_list_reverse (list);
531}
532
533static GHashTable *
534cluster_dict (s4_resultset_t *set, xmms_fetch_spec_t *spec)
535{
536 GHashTable *table;
537 GList *list = NULL((void*)0);
538
539 table = g_hash_table_new_full (g_str_hash, g_str_equal,
540 g_free, (GDestroyNotify) s4_resultset_free);
541
542 cluster_set (set, spec, table, &list);
543 g_list_free (list);
544
545 return table;
546}
547
548static xmmsv_t *
549convert_ghashtable_to_xmmsv (GHashTable *table, xmms_fetch_spec_t *spec)
550{
551 GHashTableIter iter;
552 s4_resultset_t *value;
553 const gchar *key;
554 xmmsv_t *ret;
555
556 g_hash_table_iter_init (&iter, table);
557
558 ret = xmmsv_new_dict ();
559
560 while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) {
561 xmmsv_t *converted;
562
563 if (value == NULL((void*)0)) {
564 continue;
565 }
566
567 converted = xmms_medialib_query_to_xmmsv (value, spec);
568 xmmsv_dict_set (ret, key, converted);
569 xmmsv_unref (converted);
570 }
571
572 if (xmmsv_dict_get_size (ret) == 0) {
573 xmmsv_unref (ret);
574 ret = NULL((void*)0);
575 }
576
577 return ret;
578}
579
580/* Converts an S4 resultset into an xmmsv_t, based on the fetch specification */
581xmmsv_t *
582xmms_medialib_query_to_xmmsv (s4_resultset_t *set, xmms_fetch_spec_t *spec)
583{
584 GHashTable *set_table;
585 GList *sets;
586 xmmsv_t *val, *ret = NULL((void*)0);
587 gint i;
588
589 switch (spec->type) {
590 case FETCH_COUNT:
591 ret = xmmsv_new_int (s4_resultset_get_rowcount (set));
592 break;
593 case FETCH_METADATA:
594 ret = metadata_to_xmmsv (set, spec);
595 break;
596 case FETCH_ORGANIZE:
597 ret = xmmsv_new_dict ();
598
599 for (i = 0; i < spec->data.organize.count; i++) {
600 val = xmms_medialib_query_to_xmmsv (set, spec->data.organize.data[i]);
601 if (val != NULL((void*)0)) {
602 xmmsv_dict_set (ret, spec->data.organize.keys[i], val);
603 xmmsv_unref (val);
604 }
605 }
606 break;
607 case FETCH_CLUSTER_LIST:
608 sets = cluster_list (set, spec);
609 ret = xmmsv_new_list ();
610 for (; sets != NULL((void*)0); sets = g_list_delete_link (sets, sets)) {
611 set = sets->data;
612
613 val = xmms_medialib_query_to_xmmsv (set, spec->data.cluster.data);
614 if (val != NULL((void*)0)) {
615 xmmsv_list_append (ret, val);
616 xmmsv_unref (val);
617 }
618 s4_resultset_free (set);
619 }
620 break;
621 case FETCH_CLUSTER_DICT:
622 set_table = cluster_dict (set, spec);
623 ret = convert_ghashtable_to_xmmsv (set_table, spec->data.cluster.data);
624
625 g_hash_table_destroy (set_table);
626 break;
627 default:
628 g_assert_not_reached ()do { g_assertion_message_expr ("core", "../src/xmms/medialib_query_result.c"
, 628, ((const char*) (__func__)), ((void*)0)); } while (0)
;
629 }
630
631 return ret;
632}