The old code freed nodes inline after processing them. This works fine unless the input has cycles, in which case future iterations will try to decrement in_count for the freed nodes. The new code defers freeing all nodes until the processing is done. --- coreutils/tsort.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/coreutils/tsort.c b/coreutils/tsort.c index dedb65b15..15c8ecbf2 100644 --- a/coreutils/tsort.c +++ b/coreutils/tsort.c @@ -101,6 +101,8 @@ int tsort_main(int argc UNUSED_PARAM, char **argv) ssize_t len; struct node *a; int cycles; + unsigned i; + unsigned remaining; INIT_G(); @@ -152,16 +154,17 @@ int tsort_main(int argc UNUSED_PARAM, char **argv) * - if any nodes are left, they form cycles. */ cycles = 0; - while (G.nodes_len) { + remaining = G.nodes_len; + + while (remaining) { struct node *n; - unsigned i; /* Search for first node with no incoming edges */ - for (i = 0; i < G.nodes_len; i++) { + for (i = 0; i < remaining; i++) { if (!G.nodes[i]->in_count) break; } - if (i == G.nodes_len) { + if (i == remaining) { /* Must be a cycle; arbitraily break it at node 0 */ cycles++; i = 0; @@ -170,17 +173,22 @@ int tsort_main(int argc UNUSED_PARAM, char **argv) #endif } - /* Remove the node (need no longer maintain sort) */ + /* Swap the node to the back (need no longer maintain sort) */ n = G.nodes[i]; - G.nodes[i] = G.nodes[--G.nodes_len]; + G.nodes[i] = G.nodes[--remaining]; + G.nodes[remaining] = n; /* And remove its outgoing edges */ for (i = 0; i < n->out_count; i++) n->out[i]->in_count--; - free(n->out); puts(n->name); - free(n); + } + + /* Free all nodes */ + for (i = 0; i < G.nodes_len; i++) { + free(G.nodes[i]->out); + free(G.nodes[i]); } free(G.nodes); -- 2.39.0.314.g84b9a713c41-goog _______________________________________________ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox