Challenge 2: Reintroducing the free-Before-Read Bug — Possible Solution ==================================================================== void free_list_BROKEN(Node *head) { while (head != NULL) { free(head); Node *next = head->next; // reading head AFTER it was freed head = next; } } What goes wrong: free(head) releases head's memory back to the allocator, meaning head is now a dangling pointer (per c1-7/c2-2) -- the memory it points to is no longer valid, even though the pointer variable itself still holds the same address. The very next line reads head->next, which dereferences that same now-freed pointer -- a textbook use-after-free (c2-3's own bug catalog). This is undefined behavior, not a guaranteed crash: the read might, by coincidence, still return the correct next value (if nothing has overwritten that memory yet), might return garbage, or might crash outright -- and per c2-3's own warn-box, "it didn't crash" is never proof the bug isn't real. In a longer-running or more heavily loaded program, this same code could corrupt the traversal in a way that's much harder to diagnose than an immediate crash. Why the correct version avoids this: saving next = head->next BEFORE calling free(head) reads the pointer while head's memory is still valid, capturing the value needed to continue the loop before that memory becomes inaccessible -- the free() call happens strictly after everything the loop still needs from head has already been extracted. WHY THIS WORKS AS AN ANSWER ------------------------------ This shows the exact reordering that reintroduces the bug, correctly classifies it as use-after-free/undefined behavior (not simply "wrong order"), and explicitly notes that the failure isn't guaranteed to be an obvious crash -- tying back to c2-3's own point about UB's unpredictable symptoms rather than treating this as a simple logic error.