Bug Summary

File:tools/dumpsolv.c
Warning:line 466, column 8
Array access (via field 'first') results in a null pointer dereference

Annotated Source Code

1/*
2 * Copyright (c) 2007, Novell Inc.
3 *
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <unistd.h>
11#include <string.h>
12
13static int with_attr;
14static int dump_json;
15
16#include "pool.h"
17#include "chksum.h"
18#include "repo_solv.h"
19
20
21static int
22dump_attr(Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
23{
24 const char *keyname;
25 KeyValue *kvp;
26 int indent = 0;
27
28 keyname = pool_id2str(repo->pool, key->name);
29 for (kvp = kv; (kvp = kvp->parent) != 0; indent += 2)
30 printf(" ");
31 switch(key->type)
32 {
33 case REPOKEY_TYPE_ID:
34 if (data && data->localpool)
35 kv->str = stringpool_id2str(&data->spool, kv->id);
36 else
37 kv->str = pool_dep2str(repo->pool, kv->id);
38 printf("%s: %s\n", keyname, kv->str);
39 break;
40 case REPOKEY_TYPE_CONSTANTID:
41 printf("%s: %s\n", keyname, pool_dep2str(repo->pool, kv->id));
42 break;
43 case REPOKEY_TYPE_IDARRAY:
44 if (!kv->entry)
45 printf("%s:\n%*s", keyname, indent, "");
46 if (data && data->localpool)
47 printf(" %s\n", stringpool_id2str(&data->spool, kv->id));
48 else
49 printf(" %s\n", pool_dep2str(repo->pool, kv->id));
50 break;
51 case REPOKEY_TYPE_STR:
52 printf("%s: %s\n", keyname, kv->str);
53 break;
54 case REPOKEY_TYPE_VOID:
55 printf("%s: (void)\n", keyname);
56 break;
57 case REPOKEY_TYPE_U32:
58 case REPOKEY_TYPE_CONSTANT:
59 printf("%s: %u\n", keyname, kv->num);
60 break;
61 case REPOKEY_TYPE_NUM:
62 printf("%s: %llu\n", keyname, SOLV_KV_NUM64(kv)(((unsigned long long)((kv)->num2)) << 32 | (kv)->
num)
);
63 break;
64 case REPOKEY_TYPE_BINARY:
65 if (kv->num)
66 printf("%s: %02x..%02x len %u\n", keyname, (unsigned char)kv->str[0], (unsigned char)kv->str[kv->num - 1], kv->num);
67 else
68 printf("%s: len 0\n", keyname);
69 break;
70 case REPOKEY_TYPE_DIRNUMNUMARRAY:
71 if (!kv->entry)
72 printf("%s:\n%*s", keyname, indent, "");
73 printf(" %s %u %u\n", repodata_dir2str(data, kv->id, 0), kv->num, kv->num2);
74 break;
75 case REPOKEY_TYPE_DIRSTRARRAY:
76 if (!kv->entry)
77 printf("%s:\n%*s", keyname, indent, "");
78 printf(" %s\n", repodata_dir2str(data, kv->id, kv->str));
79 break;
80 case REPOKEY_TYPE_FIXARRAY:
81 case REPOKEY_TYPE_FLEXARRAY:
82 if (!kv->entry)
83 printf("%s:\n", keyname);
84 else
85 printf("\n");
86 break;
87 default:
88 if (solv_chksum_len(key->type))
89 {
90 printf("%s: %s (%s)\n", keyname, repodata_chk2str(data, key->type, (unsigned char *)kv->str), solv_chksum_type2str(key->type));
91 break;
92 }
93 printf("%s: ?\n", keyname);
94 break;
95 }
96 return 0;
97}
98
99static const char *
100jsonstring(Pool *pool, const char *s)
101{
102 int needed = 0;
103 const unsigned char *s1;
104 char *r, *rp;
105
106 for (s1 = (const unsigned char *)s; *s1; s1++)
107 {
108 if (*s1 < 32)
109 needed += *s1 == '\n' ? 2 : 6;
110 else if (*s1 == '\\' || *s1 == '\"')
111 needed += 2;
112 else
113 needed++;
114 }
115 r = rp = pool_alloctmpspace(pool, needed + 3);
116 *rp++ = '\"';
117 for (s1 = (const unsigned char *)s; *s1; s1++)
118 {
119 if (*s1 < 32)
120 {
121 int x;
122 if (*s1 == '\n')
123 {
124 *rp++ = '\\';
125 *rp++ = 'n';
126 continue;
127 }
128 *rp++ = '\\';
129 *rp++ = 'u';
130 *rp++ = '0';
131 *rp++ = '0';
132 x = *s1 / 16;
133 *rp++ = (x < 10 ? '0' : 'a' - 10) + x;
134 x = *s1 & 15;
135 *rp++ = (x < 10 ? '0' : 'a' - 10) + x;
136 }
137 else if (*s1 == '\\' || *s1 == '\"')
138 {
139 *rp++ = '\\';
140 *rp++ = *s1;
141 }
142 else
143 *rp++ = *s1;
144 }
145 *rp++ = '\"';
146 *rp = 0;
147 return r;
148}
149
150struct cbdata {
151 unsigned char *first;
152 int nfirst;
153 int baseindent;
154};
155
156static int
157dump_attr_json(Repo *repo, Repodata *data, Repokey *key, KeyValue *kv, struct cbdata *cbdata)
158{
159 Pool *pool = repo->pool;
160 const char *keyname;
161 KeyValue *kvp;
162 int indent = cbdata->baseindent;
163 int isarray = 0;
164 const char *str;
165 int depth = 0;
166
167 keyname = pool_id2str(repo->pool, key->name);
168 for (kvp = kv; (kvp = kvp->parent) != 0; indent += 4)
169 depth++;
170 if (cbdata->nfirst < depth + 1)
171 {
172 cbdata->first = solv_realloc(cbdata->first, depth + 16);
173 memset(cbdata->first + cbdata->nfirst, 0, depth + 16 - cbdata->nfirst);
174 cbdata->nfirst = depth + 16;
175 }
176 switch(key->type)
177 {
178 case REPOKEY_TYPE_IDARRAY:
179 case REPOKEY_TYPE_DIRNUMNUMARRAY:
180 case REPOKEY_TYPE_DIRSTRARRAY:
181 isarray = 1;
182 break;
183 case REPOKEY_TYPE_FIXARRAY:
184 case REPOKEY_TYPE_FLEXARRAY:
185 isarray = 2;
186 break;
187 default:
188 break;
189 }
190 if (!isarray || !kv->entry)
191 {
192 if (cbdata->first[depth])
193 printf(",\n");
194 printf("%*s%s: ", indent, "", jsonstring(pool, keyname));
195 cbdata->first[depth] = 1;
196 }
197 if (isarray == 1 && !kv->entry)
198 printf("[\n%*s", indent + 2, "");
199 else if (isarray == 1 && kv->entry)
200 printf("%*s", indent + 2, "");
201 switch(key->type)
202 {
203 case REPOKEY_TYPE_ID:
204 if (data && data->localpool)
205 str = stringpool_id2str(&data->spool, kv->id);
206 else
207 str = pool_dep2str(repo->pool, kv->id);
208 printf("%s", jsonstring(pool, str));
209 break;
210 case REPOKEY_TYPE_CONSTANTID:
211 str = pool_dep2str(repo->pool, kv->id);
212 printf("%s", jsonstring(pool, str));
213 break;
214 case REPOKEY_TYPE_IDARRAY:
215 if (data && data->localpool)
216 str = stringpool_id2str(&data->spool, kv->id);
217 else
218 str = pool_dep2str(repo->pool, kv->id);
219 printf("%s", jsonstring(pool, str));
220 break;
221 case REPOKEY_TYPE_STR:
222 str = kv->str;
223 printf("%s", jsonstring(pool, str));
224 break;
225 case REPOKEY_TYPE_VOID:
226 printf("null");
227 break;
228 case REPOKEY_TYPE_U32:
229 case REPOKEY_TYPE_CONSTANT:
230 printf("%u", kv->num);
231 break;
232 case REPOKEY_TYPE_NUM:
233 printf("%llu", SOLV_KV_NUM64(kv)(((unsigned long long)((kv)->num2)) << 32 | (kv)->
num)
);
234 break;
235 case REPOKEY_TYPE_BINARY:
236 printf("\"<binary>\"");
237 break;
238 case REPOKEY_TYPE_DIRNUMNUMARRAY:
239 printf("{\n");
240 printf("%*s \"dir\": %s,\n", indent, "", jsonstring(pool, repodata_dir2str(data, kv->id, 0)));
241 printf("%*s \"num1\": %u,\n", indent, "", kv->num);
242 printf("%*s \"num2\": %u\n", indent, "", kv->num2);
243 printf("%*s }", indent, "");
244 break;
245 case REPOKEY_TYPE_DIRSTRARRAY:
246 printf("%s", jsonstring(pool, repodata_dir2str(data, kv->id, kv->str)));
247 break;
248 case REPOKEY_TYPE_FIXARRAY:
249 case REPOKEY_TYPE_FLEXARRAY:
250 cbdata->first[depth + 1] = 0;
251 if (!kv->entry)
252 printf("[\n");
253 else
254 {
255 if (kv->eof != 2)
256 printf("\n%*s },\n", indent, "");
257 else
258 printf("\n%*s }\n", indent, "");
259 }
260 if (kv->eof != 2)
261 printf("%*s {\n", indent, "");
262 else
263 printf("%*s]", indent, "");
264 break;
265 default:
266 if (solv_chksum_len(key->type))
267 {
268 printf("{\n");
269 printf("%*s \"value\": %s,\n", indent, "", jsonstring(pool, repodata_chk2str(data, key->type, (unsigned char *)kv->str)));
270 printf("%*s \"type\": %s\n", indent, "", jsonstring(pool, solv_chksum_type2str(key->type)));
271 printf("%*s}", indent, "");
272 break;
273 }
274 printf("\"?\"");
275 break;
276 }
277 if (isarray == 1)
278 {
279 if (!kv->eof)
280 printf(",\n");
281 else
282 printf("\n%*s]", indent, "");
283 }
284 return 0;
285}
286
287static int
288dump_repodata_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
289{
290 if (key->name == REPOSITORY_SOLVABLES)
291 return SEARCH_NEXT_SOLVABLE2;
292 if (!dump_json)
293 return dump_attr(data->repo, data, key, kv);
294 else
295 return dump_attr_json(data->repo, data, key, kv, vcbdata);
296}
297
298static void
299dump_repodata(Repo *repo)
300{
301 int i;
302 Repodata *data;
303 if (repo->nrepodata == 0)
304 return;
305 printf("repo contains %d repodata sections:\n", repo->nrepodata - 1);
306 FOR_REPODATAS(repo, i, data)for (i = 1; i < repo->nrepodata && (data = repo_id2repodata
(repo, i)); i++)
307 {
308 unsigned int j;
309 printf("\nrepodata %d has %d keys, %d schemata\n", i, data->nkeys - 1, data->nschemata - 1);
310 for (j = 1; j < data->nkeys; j++)
311 printf(" %s (type %s size %d storage %d)\n", pool_id2str(repo->pool, data->keys[j].name), pool_id2str(repo->pool, data->keys[j].type), data->keys[j].size, data->keys[j].storage);
312 if (data->localpool)
313 printf(" localpool has %d strings, size is %d\n", data->spool.nstrings, data->spool.sstrings);
314 if (data->dirpool.ndirs)
315 printf(" localpool has %d directories\n", data->dirpool.ndirs);
316 printf("\n");
317 repodata_search(data, SOLVID_META-1, 0, SEARCH_ARRAYSENTINEL(1<<10)|SEARCH_SUB(1<<9), dump_repodata_cb, 0);
318 }
319 printf("\n");
320}
321
322static void
323dump_repodata_json(Repo *repo, struct cbdata *cbdata)
324{
325 int i;
326 Repodata *data;
327 if (repo->nrepodata == 0)
328 return;
329 cbdata->baseindent = 6;
330 FOR_REPODATAS(repo, i, data)for (i = 1; i < repo->nrepodata && (data = repo_id2repodata
(repo, i)); i++)
331 repodata_search(data, SOLVID_META-1, 0, SEARCH_ARRAYSENTINEL(1<<10)|SEARCH_SUB(1<<9), dump_repodata_cb, cbdata);
332}
333
334/*
335 * dump all attributes for Id <p>
336 */
337
338void
339dump_solvable(Repo *repo, Id p, struct cbdata *cbdata)
340{
341 Dataiterator di;
342 dataiterator_init(&di, repo->pool, repo, p, 0, 0, SEARCH_ARRAYSENTINEL(1<<10)|SEARCH_SUB(1<<9));
343 if (cbdata && cbdata->first)
344 cbdata->first[0] = 0;
345 if (cbdata)
346 cbdata->baseindent = 10;
347 while (dataiterator_step(&di))
348 {
349 if (!dump_json)
350 dump_attr(repo, di.data, di.key, &di.kv);
351 else
352 dump_attr_json(repo, di.data, di.key, &di.kv, cbdata);
353 }
354 dataiterator_free(&di);
355}
356
357static int
358loadcallback(Pool *pool, Repodata *data, void *vdata)
359{
360 FILE *fp = 0;
361 int r;
362 const char *location;
363
364 location = repodata_lookup_str(data, SOLVID_META-1, REPOSITORY_LOCATION);
365 if (!location || !with_attr)
366 return 0;
367 fprintf(stderrstderr, "[Loading SOLV file %s]\n", location);
368 fp = fopen (location, "r");
369 if (!fp)
370 {
371 perror(location);
372 return 0;
373 }
374 r = repo_add_solv(data->repo, fp, REPO_USE_LOADING(1 << 3)|REPO_LOCALPOOL(1 << 2));
375 fclose(fp);
376 return !r ? 1 : 0;
377}
378
379
380static void
381usage(int status)
382{
383 fprintf( stderrstderr, "\nUsage:\n"
384 "dumpsolv [-a] [-j] [<solvfile>]\n"
385 " -a read attributes.\n"
386 " -j dump json format.\n"
387 );
388 exit(status);
389}
390
391int main(int argc, char **argv)
392{
393 Repo *repo;
394 Pool *pool;
395 int c, i, j, n;
396 Solvable *s;
397
398 pool = pool_create();
399 pool_setloadcallback(pool, loadcallback, 0);
400
401 while ((c = getopt(argc, argv, "haj")) >= 0)
1
Assuming the condition is false
2
Loop condition is false. Execution continues on line 419
402 {
403 switch(c)
404 {
405 case 'h':
406 usage(0);
407 break;
408 case 'a':
409 with_attr = 1;
410 break;
411 case 'j':
412 dump_json = 1;
413 break;
414 default:
415 usage(1);
416 break;
417 }
418 }
419 if (!dump_json)
3
Assuming 'dump_json' is not equal to 0
4
Taking false branch
420 pool_setdebuglevel(pool, 1);
421 if (dump_json)
5
Taking true branch
422 pool->debugmask |= SOLV_DEBUG_TO_STDERR(1<<30);
423 for (; optind < argc; optind++)
6
Loop condition is false. Execution continues on line 437
424 {
425 if (freopen(argv[optind], "r", stdinstdin) == 0)
426 {
427 perror(argv[optind]);
428 exit(1);
429 }
430 repo = repo_create(pool, argv[optind]);
431 if (repo_add_solv(repo, stdinstdin, 0))
432 {
433 fprintf(stderrstderr, "could not read repository: %s\n", pool_errstr(pool));
434 exit(1);
435 }
436 }
437 if (!pool->urepos)
7
Assuming the condition is false
8
Taking false branch
438 {
439 repo = repo_create(pool, argc != 1 ? argv[1] : "<stdin>");
440 if (repo_add_solv(repo, stdinstdin, 0))
441 {
442 fprintf(stderrstderr, "could not read repository: %s\n", pool_errstr(pool));
443 exit(1);
444 }
445 }
446
447 if (dump_json)
9
Taking true branch
448 {
449 int openrepo = 0;
450 struct cbdata cbdata;
451
452 memset(&cbdata, 0, sizeof(cbdata));
10
Value assigned to 'cbdata.first'
453 printf("{\n");
454 printf(" \"repositories\": [\n");
455 FOR_REPOS(j, repo)for (j = 1; j < pool->nrepos; j++) if ((repo = pool->
repos[j]) == 0) continue; else
456 {
457 int open = 0;
458
459 if (openrepo)
11
Taking false branch
460 printf("\n },");
461 printf(" {\n");
462 openrepo = 1;
463 if (cbdata.first)
12
Assuming pointer value is null
13
Taking false branch
464 cbdata.first[0] = 0;
465 dump_repodata_json(repo, &cbdata);
466 if (cbdata.first[0])
14
Array access (via field 'first') results in a null pointer dereference
467 printf(",\n");
468 printf(" \"solvables\": [\n");
469 FOR_REPO_SOLVABLES(repo, i, s)for (i = (repo)->start, s = (repo)->pool->solvables +
i; i < (repo)->end; i++, s = (repo)->pool->solvables
+ i) if (s->repo != (repo)) continue; else
470 {
471 if (open)
472 printf("\n },\n");
473 printf(" {\n");
474 open = 1;
475 dump_solvable(repo, i, &cbdata);
476 }
477 if (open)
478 printf("\n }\n");
479 printf(" ]\n");
480 }
481 if (openrepo)
482 printf(" }\n");
483 printf(" ]\n");
484 printf("}\n");
485 solv_free(cbdata.first);
486 }
487 else
488 {
489 printf("pool contains %d strings, %d rels, string size is %d\n", pool->ss.nstrings, pool->nrels, pool->ss.sstrings);
490 n = 0;
491 FOR_REPOS(j, repo)for (j = 1; j < pool->nrepos; j++) if ((repo = pool->
repos[j]) == 0) continue; else
492 {
493 dump_repodata(repo);
494 printf("repo %d contains %d solvables\n", j, repo->nsolvables);
495 printf("repo start: %d end: %d\n", repo->start, repo->end);
496 FOR_REPO_SOLVABLES(repo, i, s)for (i = (repo)->start, s = (repo)->pool->solvables +
i; i < (repo)->end; i++, s = (repo)->pool->solvables
+ i) if (s->repo != (repo)) continue; else
497 {
498 n++;
499 printf("\n");
500 printf("solvable %d (%d):\n", n, i);
501 dump_solvable(repo, i, 0);
502 }
503 }
504 }
505 pool_free(pool);
506 exit(0);
507}