Bug Summary

File:src/usr.bin/tsort/tsort.c
Warning:line 729, column 31
Access to field 'from' results in a dereference of a null pointer (loaded from variable 't')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name tsort.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/tsort/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/tsort/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/tsort/tsort.c
1/* $OpenBSD: tsort.c,v 1.37 2019/07/11 17:28:32 mestre Exp $ */
2/* ex:ts=8 sw=4:
3 *
4 * Copyright (c) 1999-2004 Marc Espie <espie@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <assert.h>
20#include <ctype.h>
21#include <err.h>
22#include <limits.h>
23#include <stddef.h>
24#include <stdio.h>
25#include <stdint.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include <ohash.h>
30
31/* The complexity of topological sorting is O(e), where e is the
32 * size of input. While reading input, vertices have to be identified,
33 * thus add the complexity of e keys retrieval among v keys using
34 * an appropriate data structure. This program uses open double hashing
35 * for that purpose. See Knuth for the expected complexity of double
36 * hashing (Brent variation should probably be used if v << e, as a user
37 * option).
38 *
39 * The algorithm used for longest cycle reporting is accurate, but somewhat
40 * expensive. It may need to build all free paths of the graph (a free
41 * path is a path that never goes twice through the same node), whose
42 * number can be as high as O(2^e). Usually, the number of free paths is
43 * much smaller though. This program's author does not believe that a
44 * significantly better worst-case complexity algorithm exists.
45 *
46 * In case of a hints file, the set of minimal nodes is maintained as a
47 * heap. The resulting complexity is O(e+v log v) for the worst case.
48 * The average should actually be near O(e).
49 *
50 * If the hints file is incomplete, there is some extra complexity incurred
51 * by make_transparent, which does propagate order values to unmarked
52 * nodes. In the worst case, make_transparent is O(e u),
53 * where u is the number of originally unmarked nodes.
54 * In practice, it is much faster.
55 *
56 * The simple topological sort algorithm detects cycles. This program
57 * goes further, breaking cycles through the use of simple heuristics.
58 * Each cycle break checks the whole set of nodes, hence if c cycles break
59 * are needed, this is an extra cost of O(c v).
60 *
61 * Possible heuristics are as follows:
62 * - break cycle at node with lowest number of predecessors (default case),
63 * - break longest cycle at node with lowest number of predecessors,
64 * - break cycle at next node from the hints file.
65 *
66 * Except for the hints file case, which sets an explicit constraint on
67 * which cycle to break, those heuristics locally result in the smallest
68 * number of broken edges.
69 *
70 * Those are admittedly greedy strategies, as is the selection of the next
71 * node from the hints file amongst equivalent candidates that is used for
72 * `stable' topological sorting.
73 */
74
75#ifdef __GNUC__4
76#define UNUSED__attribute__((unused)) __attribute__((unused))
77#else
78#define UNUSED__attribute__((unused))
79#endif
80
81struct node;
82
83/* The set of arcs from a given node is stored as a linked list. */
84struct link {
85 struct link *next;
86 struct node *node;
87};
88
89#define NO_ORDER(2147483647 *2U +1U) UINT_MAX(2147483647 *2U +1U)
90
91struct node {
92 unsigned int refs; /* Number of arcs left, coming into this node.
93 * Note that nodes with a null count can't
94 * be part of cycles. */
95 unsigned int order; /* Order of nodes according to a hint file. */
96
97 struct link *arcs; /* List of forward arcs. */
98
99 /* Cycle detection algorithms build a free path of nodes. */
100 struct node *from; /* Previous node in the current path. */
101 struct link *traverse; /* Next link to traverse when backtracking. */
102 unsigned int mark; /* Mark processed nodes in cycle discovery. */
103
104 char k[1]; /* Name of this node. */
105};
106
107#define HASH_START9 9
108
109struct array {
110 unsigned int entries;
111 struct node **t;
112};
113
114static void nodes_init(struct ohash *);
115static struct node *node_lookup(struct ohash *, const char *, const char *);
116static __dead__attribute__((__noreturn__)) void usage(void);
117static struct node *new_node(const char *, const char *);
118
119static unsigned int read_pairs(FILE *, struct ohash *, int,
120 const char *, unsigned int, int);
121static void split_nodes(struct ohash *, struct array *, struct array *);
122static void make_transparent(struct ohash *);
123static void insert_arc(struct node *, struct node *);
124
125#ifdef DEBUG
126static void dump_node(struct node *);
127static void dump_array(struct array *);
128static void dump_hash(struct ohash *);
129#endif
130static unsigned int read_hints(FILE *, struct ohash *, int,
131 const char *, unsigned int);
132static struct node *find_smallest_node(struct array *);
133static struct node *find_good_cycle_break(struct array *);
134static void print_cycle(struct array *);
135static struct node *find_cycle_from(struct node *, struct array *);
136static struct node *find_predecessor(struct array *, struct node *);
137static unsigned int traverse_node(struct node *, unsigned int, struct array *);
138static struct node *find_longest_cycle(struct array *, struct array *);
139static struct node *find_normal_cycle(struct array *, struct array *);
140
141static void heap_down(struct array *, unsigned int);
142static void heapify(struct array *, int);
143static struct node *dequeue(struct array *);
144static void enqueue(struct array *, struct node *);
145
146
147
148static void *hash_calloc(size_t, size_t, void *);
149static void hash_free(void *, void *);
150static void* entry_alloc(size_t, void *);
151static void *ereallocarray(void *, size_t, size_t);
152static void *emem(void *);
153#define DEBUG_TRAVERSE0 0
154static struct ohash_info node_info = {
155 offsetof(struct node, k)__builtin_offsetof(struct node, k), NULL((void*)0), hash_calloc, hash_free, entry_alloc };
156static void parse_args(int, char *[], struct ohash *);
157static int tsort(struct ohash *);
158
159static int quiet_flag, long_flag,
160 warn_flag, hints_flag, verbose_flag;
161
162
163int main(int, char *[]);
164
165/***
166 *** Memory handling.
167 ***/
168
169static void *
170emem(void *p)
171{
172 if (p)
173 return p;
174 else
175 errx(1, "Memory exhausted");
176}
177
178static void *
179hash_calloc(size_t n, size_t s, void *u UNUSED__attribute__((unused)))
180{
181 return emem(calloc(n, s));
182}
183
184static void
185hash_free(void *p, void *u UNUSED__attribute__((unused)))
186{
187 free(p);
188}
189
190static void *
191entry_alloc(size_t s, void *u UNUSED__attribute__((unused)))
192{
193 return ereallocarray(NULL((void*)0), 1, s);
194}
195
196static void *
197ereallocarray(void *p, size_t n, size_t s)
198{
199 return emem(reallocarray(p, n, s));
200}
201
202
203/***
204 *** Hash table.
205 ***/
206
207/* Inserting and finding nodes in the hash structure.
208 * We handle interval strings for efficiency wrt fgetln. */
209static struct node *
210new_node(const char *start, const char *end)
211{
212 struct node *n;
213
214 n = ohash_create_entry(&node_info, start, &end);
215 n->from = NULL((void*)0);
216 n->arcs = NULL((void*)0);
217 n->refs = 0;
218 n->mark = 0;
219 n->order = NO_ORDER(2147483647 *2U +1U);
220 n->traverse = NULL((void*)0);
221 return n;
222}
223
224
225static void
226nodes_init(struct ohash *h)
227{
228 ohash_init(h, HASH_START9, &node_info);
229}
230
231static struct node *
232node_lookup(struct ohash *h, const char *start, const char *end)
233{
234 unsigned int i;
235 struct node * n;
236
237 i = ohash_qlookupi(h, start, &end);
238
239 n = ohash_find(h, i);
240 if (n == NULL((void*)0))
241 n = ohash_insert(h, i, new_node(start, end));
242 return n;
243}
244
245#ifdef DEBUG
246static void
247dump_node(struct node *n)
248{
249 struct link *l;
250
251 if (n->refs == 0)
252 return;
253 printf("%s (%u/%u): ", n->k, n->order, n->refs);
254 for (l = n->arcs; l != NULL((void*)0); l = l->next)
255 if (n->refs != 0)
256 printf("%s(%u/%u) ", l->node->k, l->node->order, l->node->refs);
257 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
258}
259
260static void
261dump_array(struct array *a)
262{
263 unsigned int i;
264
265 for (i = 0; i < a->entries; i++)
266 dump_node(a->t[i]);
267}
268
269static void
270dump_hash(struct ohash *h)
271{
272 unsigned int i;
273 struct node *n;
274
275 for (n = ohash_first(h, &i); n != NULL((void*)0); n = ohash_next(h, &i))
276 dump_node(n);
277}
278#endif
279
280/***
281 *** Reading data.
282 ***/
283
284static void
285insert_arc(struct node *a, struct node *b)
286{
287 struct link *l;
288
289 /* Check that this arc is not already present. */
290 for (l = a->arcs; l != NULL((void*)0); l = l->next) {
291 if (l->node == b)
292 return;
293 }
294 b->refs++;
295 l = ereallocarray(NULL((void*)0), 1, sizeof(struct link));
296 l->node = b;
297 l->next = a->arcs;
298 a->arcs = l;
299}
300
301static unsigned int
302read_pairs(FILE *f, struct ohash *h, int reverse, const char *name,
303 unsigned int order, int hint)
304{
305 int toggle;
306 struct node *a;
307 size_t size;
308 char *str;
309
310 toggle = 1;
311 a = NULL((void*)0);
312
313 while ((str = fgetln(f, &size)) != NULL((void*)0)) {
314 char *sentinel;
315
316 sentinel = str + size;
317 for (;;) {
318 char *e;
319
320 while (str < sentinel &&
321 isspace((unsigned char)*str))
322 str++;
323 if (str == sentinel)
324 break;
325 for (e = str;
326 e < sentinel && !isspace((unsigned char)*e); e++)
327 continue;
328 if (toggle) {
329 a = node_lookup(h, str, e);
330 if (a->order == NO_ORDER(2147483647 *2U +1U) && hint)
331 a->order = order++;
332 } else {
333 struct node *b;
334
335 b = node_lookup(h, str, e);
336 assert(a != NULL)((a != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.bin/tsort/tsort.c"
, 336, __func__, "a != NULL"))
;
337 if (b != a) {
338 if (reverse)
339 insert_arc(b, a);
340 else
341 insert_arc(a, b);
342 }
343 }
344 toggle = !toggle;
345 str = e;
346 }
347 }
348 if (toggle == 0)
349 errx(1, "odd number of node names in %s", name);
350 if (!feof(f)(!__isthreaded ? (((f)->_flags & 0x0020) != 0) : (feof
)(f))
)
351 err(1, "error reading %s", name);
352 return order;
353}
354
355static unsigned int
356read_hints(FILE *f, struct ohash *h, int quiet, const char *name,
357 unsigned int order)
358{
359 char *str;
360 size_t size;
361
362 while ((str = fgetln(f, &size)) != NULL((void*)0)) {
363 char *sentinel;
364
365 sentinel = str + size;
366 for (;;) {
367 char *e;
368 struct node *a;
369
370 while (str < sentinel && isspace((unsigned char)*str))
371 str++;
372 if (str == sentinel)
373 break;
374 for (e = str;
375 e < sentinel && !isspace((unsigned char)*e); e++)
376 continue;
377 a = node_lookup(h, str, e);
378 if (a->order != NO_ORDER(2147483647 *2U +1U)) {
379 if (!quiet)
380 warnx(
381 "duplicate node %s in hints file %s",
382 a->k, name);
383 } else
384 a->order = order++;
385 str = e;
386 }
387 }
388 if (!feof(f)(!__isthreaded ? (((f)->_flags & 0x0020) != 0) : (feof
)(f))
)
389 err(1, "error reading %s", name);
390 return order;
391}
392
393
394/***
395 *** Standard heap handling routines.
396 ***/
397
398static void
399heap_down(struct array *h, unsigned int i)
400{
401 unsigned int j;
402 struct node *swap;
403
404 for (; (j=2*i+1) < h->entries; i = j) {
405 if (j+1 < h->entries && h->t[j+1]->order < h->t[j]->order)
406 j++;
407 if (h->t[i]->order <= h->t[j]->order)
408 break;
409 swap = h->t[i];
410 h->t[i] = h->t[j];
411 h->t[j] = swap;
412 }
413}
414
415static void
416heapify(struct array *h, int verbose)
417{
418 unsigned int i;
419
420 for (i = h->entries; i != 0;) {
421 if (h->t[--i]->order == NO_ORDER(2147483647 *2U +1U) && verbose)
422 warnx("node %s absent from hints file", h->t[i]->k);
423 heap_down(h, i);
424 }
425}
426
427#define DEQUEUE(h)( hints_flag ? dequeue(h) : (h)->t[--(h)->entries] ) ( hints_flag ? dequeue(h) : (h)->t[--(h)->entries] )
428
429static struct node *
430dequeue(struct array *h)
431{
432 struct node *n;
433
434 if (h->entries == 0)
435 n = NULL((void*)0);
436 else {
437 n = h->t[0];
438 if (--h->entries != 0) {
439 h->t[0] = h->t[h->entries];
440 heap_down(h, 0);
441 }
442 }
443 return n;
444}
445
446#define ENQUEUE(h, n)do { if (hints_flag) enqueue((h), (n)); else (h)->t[(h)->
entries++] = (n); } while(0);
do { \
447 if (hints_flag) \
448 enqueue((h), (n)); \
449 else \
450 (h)->t[(h)->entries++] = (n); \
451 } while(0);
452
453static void
454enqueue(struct array *h, struct node *n)
455{
456 unsigned int i, j;
457 struct node *swap;
458
459 h->t[h->entries++] = n;
460 for (i = h->entries-1; i > 0; i = j) {
461 j = (i-1)/2;
462 if (h->t[j]->order < h->t[i]->order)
463 break;
464 swap = h->t[j];
465 h->t[j] = h->t[i];
466 h->t[i] = swap;
467 }
468}
469
470/* Nodes without order should not hinder direct dependencies.
471 * Iterate until no nodes are left.
472 */
473static void
474make_transparent(struct ohash *hash)
475{
476 struct node *n;
477 unsigned int i;
478 struct link *l;
479 int adjusted;
480 int bad;
481 unsigned int min;
482
483 /* first try to solve complete nodes */
484 do {
485 adjusted = 0;
486 bad = 0;
487 for (n = ohash_first(hash, &i); n != NULL((void*)0);
488 n = ohash_next(hash, &i)) {
489 if (n->order == NO_ORDER(2147483647 *2U +1U)) {
490 min = NO_ORDER(2147483647 *2U +1U);
491
492 for (l = n->arcs; l != NULL((void*)0); l = l->next) {
493 /* unsolved node -> delay resolution */
494 if (l->node->order == NO_ORDER(2147483647 *2U +1U)) {
495 bad = 1;
496 break;
497 } else if (l->node->order < min)
498 min = l->node->order;
499 }
500 if (min < NO_ORDER(2147483647 *2U +1U) && l == NULL((void*)0)) {
501 n->order = min;
502 adjusted = 1;
503 }
504 }
505 }
506
507 } while (adjusted);
508
509 /* then, if incomplete nodes are left, do them */
510 if (bad) do {
511 adjusted = 0;
512 for (n = ohash_first(hash, &i); n != NULL((void*)0);
513 n = ohash_next(hash, &i))
514 if (n->order == NO_ORDER(2147483647 *2U +1U))
515 for (l = n->arcs; l != NULL((void*)0); l = l->next)
516 if (l->node->order < n->order) {
517 n->order = l->node->order;
518 adjusted = 1;
519 }
520 } while (adjusted);
521}
522
523
524/***
525 *** Search through hash array for nodes.
526 ***/
527
528/* Split nodes into unrefed nodes/live nodes. */
529static void
530split_nodes(struct ohash *hash, struct array *heap, struct array *remaining)
531{
532
533 struct node *n;
534 unsigned int i;
535
536 heap->t = ereallocarray(NULL((void*)0), ohash_entries(hash),
537 sizeof(struct node *));
538 remaining->t = ereallocarray(NULL((void*)0), ohash_entries(hash),
539 sizeof(struct node *));
540 heap->entries = 0;
541 remaining->entries = 0;
542
543 for (n = ohash_first(hash, &i); n != NULL((void*)0); n = ohash_next(hash, &i)) {
544 if (n->refs == 0)
545 heap->t[heap->entries++] = n;
546 else
547 remaining->t[remaining->entries++] = n;
548 }
549}
550
551/* Good point to break a cycle: live node with as few refs as possible. */
552static struct node *
553find_good_cycle_break(struct array *h)
554{
555 unsigned int i;
556 unsigned int best;
557 struct node *u;
558
559 best = UINT_MAX(2147483647 *2U +1U);
560 u = NULL((void*)0);
561
562 assert(h->entries != 0)((h->entries != 0) ? (void)0 : __assert2("/usr/src/usr.bin/tsort/tsort.c"
, 562, __func__, "h->entries != 0"))
;
563 for (i = 0; i < h->entries; i++) {
564 struct node *n = h->t[i];
565 /* No need to look further. */
566 if (n->refs == 1)
567 return n;
568 if (n->refs != 0 && n->refs < best) {
569 best = n->refs;
570 u = n;
571 }
572 }
573 assert(u != NULL)((u != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.bin/tsort/tsort.c"
, 573, __func__, "u != NULL"))
;
574 return u;
575}
576
577/* Retrieve the node with the smallest order. */
578static struct node *
579find_smallest_node(struct array *h)
580{
581 unsigned int i;
582 unsigned int best;
583 struct node *u;
584
585 best = UINT_MAX(2147483647 *2U +1U);
586 u = NULL((void*)0);
587
588 assert(h->entries != 0)((h->entries != 0) ? (void)0 : __assert2("/usr/src/usr.bin/tsort/tsort.c"
, 588, __func__, "h->entries != 0"))
;
589 for (i = 0; i < h->entries; i++) {
590 struct node *n = h->t[i];
591 if (n->refs != 0 && n->order < best) {
592 best = n->order;
593 u = n;
594 }
595 }
596 assert(u != NULL)((u != ((void*)0)) ? (void)0 : __assert2("/usr/src/usr.bin/tsort/tsort.c"
, 596, __func__, "u != NULL"))
;
597 return u;
598}
599
600
601/***
602 *** Graph algorithms.
603 ***/
604
605/* Explore the nodes reachable from i to find a cycle, store it in c.
606 * This may fail. */
607static struct node *
608find_cycle_from(struct node *i, struct array *c)
609{
610 struct node *n;
611
612 n = i;
613 /* XXX Previous cycle findings may have left this pointer non-null. */
614 i->from = NULL((void*)0);
615
616 for (;;) {
617 /* Note that all marks are reversed before this code exits. */
618 n->mark = 1;
619 if (n->traverse)
620 n->traverse = n->traverse->next;
621 else
622 n->traverse = n->arcs;
623 /* Skip over dead nodes. */
624 while (n->traverse && n->traverse->node->refs == 0)
625 n->traverse = n->traverse->next;
626 if (n->traverse) {
627 struct node *go = n->traverse->node;
628
629 if (go->mark) {
630 c->entries = 0;
631 for (; n != NULL((void*)0) && n != go; n = n->from) {
632 c->t[c->entries++] = n;
633 n->mark = 0;
634 }
635 for (; n != NULL((void*)0); n = n->from)
636 n->mark = 0;
637 c->t[c->entries++] = go;
638 return go;
639 } else {
640 go->from = n;
641 n = go;
642 }
643 } else {
644 n->mark = 0;
645 n = n->from;
646 if (n == NULL((void*)0))
647 return NULL((void*)0);
648 }
649 }
650}
651
652/* Find a live predecessor of node n. This is a slow routine, as it needs
653 * to go through the whole array, but it is not needed often.
654 */
655static struct node *
656find_predecessor(struct array *a, struct node *n)
657{
658 unsigned int i;
659
660 for (i = 0; i < a->entries; i++) {
661 struct node *m;
662
663 m = a->t[i];
664 if (m->refs != 0) {
665 struct link *l;
666
667 for (l = m->arcs; l != NULL((void*)0); l = l->next)
668 if (l->node == n)
669 return m;
670 }
671 }
672 assert(1 == 0)((1 == 0) ? (void)0 : __assert2("/usr/src/usr.bin/tsort/tsort.c"
, 672, __func__, "1 == 0"))
;
673 return NULL((void*)0);
674}
675
676/* Traverse all strongly connected components reachable from node n.
677 Start numbering them at o. Return the maximum order reached.
678 Update the largest cycle found so far.
679 */
680static unsigned int
681traverse_node(struct node *n, unsigned int o, struct array *c)
682{
683 unsigned int min, max;
684
685 n->from = NULL((void*)0);
9
Null pointer value stored to field 'from'
686 min = o;
687 max = ++o;
688
689 for (;;) {
10
Loop condition is true. Entering loop body
690 n->mark = o;
691 if (DEBUG_TRAVERSE0)
11
Taking false branch
692 printf("%s(%u) ", n->k, n->mark);
693 /* Find next arc to explore. */
694 if (n->traverse)
12
Assuming field 'traverse' is null
13
Taking false branch
695 n->traverse = n->traverse->next;
696 else
697 n->traverse = n->arcs;
698 /* Skip over dead nodes. */
699 while (n->traverse && n->traverse->node->refs == 0)
14
Assuming field 'traverse' is non-null
15
Assuming field 'refs' is not equal to 0
16
Loop condition is false. Execution continues on line 702
700 n->traverse = n->traverse->next;
701 /* If arc left. */
702 if (n->traverse
16.1
Field 'traverse' is non-null
) {
17
Taking true branch
703 struct node *go;
704
705 go = n->traverse->node;
706 /* Optimisation: if go->mark < min, we already
707 * visited this strongly-connected component in
708 * a previous pass. Hence, this can yield no new
709 * cycle. */
710
711 /* Not part of the current path: go for it. */
712 if (go->mark == 0 || go->mark == min) {
18
Assuming field 'mark' is not equal to 0
19
Assuming 'min' is not equal to field 'mark'
20
Taking false branch
713 go->from = n;
714 n = go;
715 o++;
716 if (o > max)
717 max = o;
718 /* Part of the current path: check cycle length. */
719 } else if (go->mark > min
20.1
'min' is < field 'mark'
) {
21
Taking true branch
720 if (DEBUG_TRAVERSE0)
22
Taking false branch
721 printf("%d\n", o - go->mark + 1);
722 if (o - go->mark + 1 > c->entries) {
23
Assuming the condition is true
24
Taking true branch
723 struct node *t;
724 unsigned int i;
725
726 c->entries = o - go->mark + 1;
727 i = 0;
728 c->t[i++] = go;
729 for (t = n; t
27.1
't' is not equal to 'go'
!= go
; t = t->from)
25
Assuming 't' is not equal to 'go'
26
Loop condition is true. Entering loop body
27
Null pointer value stored to 't'
28
Loop condition is true. Entering loop body
29
Access to field 'from' results in a dereference of a null pointer (loaded from variable 't')
730 c->t[i++] = t;
731 }
732 }
733
734 /* No arc left: backtrack. */
735 } else {
736 n->mark = min;
737 n = n->from;
738 if (!n)
739 return max;
740 o--;
741 }
742 }
743}
744
745static void
746print_cycle(struct array *c)
747{
748 unsigned int i;
749
750 /* Printing in reverse order, since cycle discoveries finds reverse
751 * edges. */
752 for (i = c->entries; i != 0;) {
753 i--;
754 warnx("%s", c->t[i]->k);
755 }
756}
757
758static struct node *
759find_longest_cycle(struct array *h, struct array *c)
760{
761 unsigned int i;
762 unsigned int o;
763 unsigned int best;
764 struct node *n;
765 static int notfirst = 0;
766
767 assert(h->entries != 0)((h->entries != 0) ? (void)0 : __assert2("/usr/src/usr.bin/tsort/tsort.c"
, 767, __func__, "h->entries != 0"))
;
1
Assuming field 'entries' is not equal to 0
2
'?' condition is true
768
769 /* No cycle found yet. */
770 c->entries = 0;
771
772 /* Reset the set of marks, except the first time around. */
773 if (notfirst
2.1
'notfirst' is 0
) {
3
Taking false branch
774 for (i = 0; i < h->entries; i++)
775 h->t[i]->mark = 0;
776 } else
777 notfirst = 1;
778
779 o = 0;
780
781 /* Traverse the array. Each unmarked, live node heralds a
782 * new set of strongly connected components. */
783 for (i = 0; i
3.1
'i' is < field 'entries'
< h->entries; i++) {
4
Loop condition is true. Entering loop body
784 n = h->t[i];
785 if (n->refs != 0 && n->mark == 0) {
5
Assuming field 'refs' is not equal to 0
6
Assuming field 'mark' is equal to 0
7
Taking true branch
786 /* Each call to traverse_node uses a separate
787 * interval of numbers to mark nodes. */
788 o++;
789 o = traverse_node(n, o, c);
8
Calling 'traverse_node'
790 }
791 }
792
793 assert(c->entries != 0)((c->entries != 0) ? (void)0 : __assert2("/usr/src/usr.bin/tsort/tsort.c"
, 793, __func__, "c->entries != 0"))
;
794 n = c->t[0];
795 best = n->refs;
796 for (i = 0; i < c->entries; i++) {
797 if (c->t[i]->refs < best) {
798 n = c->t[i];
799 best = n->refs;
800 }
801 }
802 return n;
803}
804
805static struct node *
806find_normal_cycle(struct array *h, struct array *c)
807{
808 struct node *b, *n;
809
810 if (hints_flag)
811 n = find_smallest_node(h);
812 else
813 n = find_good_cycle_break(h);
814 while ((b = find_cycle_from(n, c)) == NULL((void*)0))
815 n = find_predecessor(h, n);
816 return b;
817}
818
819
820#define plural(n)((n) > 1 ? "s" : "") ((n) > 1 ? "s" : "")
821
822static void
823parse_args(int argc, char *argv[], struct ohash *pairs)
824{
825 int c;
826 unsigned int order;
827 int reverse_flag;
828 const char **files;
829 int i, j;
830
831 i = 0;
832
833 reverse_flag = quiet_flag = long_flag =
834 warn_flag = hints_flag = verbose_flag = 0;
835 /* argc is good enough, as we start at argv[1] */
836 files = ereallocarray(NULL((void*)0), argc, sizeof (char *));
837 while ((c = getopt(argc, argv, "h:flqrvw")) != -1) {
838 switch(c) {
839 case 'h':
840 files[i++] = optarg;
841 hints_flag = 1;
842 break;
843 /*FALLTHRU*/
844 case 'f':
845 hints_flag = 2;
846 break;
847 case 'l':
848 long_flag = 1;
849 break;
850 case 'q':
851 quiet_flag = 1;
852 break;
853 case 'r':
854 reverse_flag = 1;
855 break;
856 case 'v':
857 verbose_flag = 1;
858 break;
859 case 'w':
860 warn_flag = 1;
861 break;
862 default:
863 usage();
864 }
865 }
866
867 argc -= optind;
868 argv += optind;
869
870 switch(argc) {
871 case 1:
872 files[i++] = argv[0];
873 break;
874 case 0:
875 break;
876 default:
877 usage();
878 }
879
880 files[i] = NULL((void*)0);
881
882 nodes_init(pairs);
883 order = 0;
884
885 for (j = 0; j != i-argc; j++) {
886 FILE *f;
887
888 f = fopen(files[j], "r");
889 if (f == NULL((void*)0))
890 err(1, "Can't open hint file %s", files[i]);
891 order = read_hints(f, pairs, quiet_flag, files[i], order);
892 fclose(f);
893 }
894 free(files);
895
896 if (argc == 1) {
897 FILE *f;
898
899 f = fopen(argv[0], "r");
900 if (f == NULL((void*)0))
901 err(1, "Can't open file %s", argv[0]);
902 order = read_pairs(f, pairs, reverse_flag, argv[0], order,
903 hints_flag == 2);
904 fclose(f);
905 } else {
906 order = read_pairs(stdin(&__sF[0]), pairs, reverse_flag, "stdin",
907 order, hints_flag == 2);
908 }
909}
910
911static int
912tsort(struct ohash *pairs)
913{
914 struct array aux; /* Unrefed nodes/cycle reporting. */
915 struct array remaining;
916 unsigned int broken_arcs, broken_cycles;
917 unsigned int left;
918
919 broken_arcs = 0;
920 broken_cycles = 0;
921
922 if (hints_flag)
923 make_transparent(pairs);
924 split_nodes(pairs, &aux, &remaining);
925 ohash_delete(pairs);
926
927 if (hints_flag)
928 heapify(&aux, verbose_flag);
929
930 left = remaining.entries + aux.entries;
931 while (left != 0) {
932
933 /* Standard topological sort. */
934 while (aux.entries) {
935 struct link *l;
936 struct node *n;
937
938 n = DEQUEUE(&aux)( hints_flag ? dequeue(&aux) : (&aux)->t[--(&aux
)->entries] )
;
939 printf("%s\n", n->k);
940 left--;
941 /* We can't free nodes, as we don't know which
942 * entry we can remove in the hash table. We
943 * rely on refs == 0 to recognize live nodes.
944 * Decrease ref count of live nodes, enter new
945 * candidates into the unrefed list. */
946 for (l = n->arcs; l != NULL((void*)0); l = l->next)
947 if (l->node->refs != 0 &&
948 --l->node->refs == 0) {
949 ENQUEUE(&aux, l->node)do { if (hints_flag) enqueue((&aux), (l->node)); else (
&aux)->t[(&aux)->entries++] = (l->node); } while
(0);
;
950 }
951 }
952 /* There are still cycles to break. */
953 if (left != 0) {
954 struct node *n;
955
956 broken_cycles++;
957 /* XXX Simple cycle detection and long cycle
958 * detection are mutually exclusive. */
959
960 if (long_flag)
961 n = find_longest_cycle(&remaining, &aux);
962 else
963 n = find_normal_cycle(&remaining, &aux);
964
965 if (!quiet_flag) {
966 warnx("cycle in data");
967 print_cycle(&aux);
968 }
969
970 if (verbose_flag)
971 warnx("%u edge%s broken", n->refs,
972 plural(n->refs)((n->refs) > 1 ? "s" : ""));
973 broken_arcs += n->refs;
974 n->refs = 0;
975 /* Reinitialization, cycle reporting uses aux. */
976 aux.t[0] = n;
977 aux.entries = 1;
978 }
979 }
980 if (verbose_flag && broken_cycles != 0)
981 warnx("%u cycle%s broken, for a total of %u edge%s",
982 broken_cycles, plural(broken_cycles)((broken_cycles) > 1 ? "s" : ""),
983 broken_arcs, plural(broken_arcs)((broken_arcs) > 1 ? "s" : ""));
984 if (warn_flag)
985 return (broken_cycles < 256 ? broken_cycles : 255);
986 else
987 return (0);
988}
989
990int
991main(int argc, char *argv[])
992{
993 struct ohash pairs;
994
995 if (pledge("stdio rpath", NULL((void*)0)) == -1)
996 err(1, "pledge");
997
998 parse_args(argc, argv, &pairs);
999
1000 if (pledge("stdio", NULL((void*)0)) == -1)
1001 err(1, "pledge");
1002
1003 return tsort(&pairs);
1004}
1005
1006
1007extern char *__progname;
1008
1009static void
1010usage(void)
1011{
1012 fprintf(stderr(&__sF[2]), "Usage: %s [-flqrvw] [-h file] [file]\n", __progname);
1013 exit(1);
1014}