Complex software will be guaranteed to have bugs in it. And most of the bugs are caused by state changes.
The human mind has limited capacity of keeping track of state (data, variables.) Hence, there is a discrepancy between what the state looks like in the programmer's mind, and what it actually looks like.
How does state change?
Where in the code does the state change?
When does the state change?
In what order does the state change?
And even... why doest the state change?
The mental picture of those, formed by the programmer, is very poor.
There is of course a paradigm where state-change plays a zero roll: functional programming. But despite decades of trying, we have not been able to practically use that in complex software. Mainly because the real world deals with state. Try making a video game that carries no state!
John Carmack once did an impromptu talk on functional programming and video games, and made in interesting observation that you could write an AI/sim that takes the entire world as function input, and produces the entire world as its output.
About John's example of a one-person hallway... I think the solution is simple. Input for hall-entering needs more than the current entity. It needs a list of all other entities that want to enter. Then use a heuristic to choose which one can actually enter. Done.
So yeah... complex state changes. As long as we have not harnessed the complexity of state, I find it pretty futile to crusade against C's unsafe memory referencing, e.g. A bug caused by following a dangling pointer is so shallow, compared to a bug caused by asynchronous state changes racing to completion. Throw in multiple threads, multi-player, and it will be too hard to reason about.