In Racket you can't get a stack overflow.
At the time a potential stack overflow is detected, the oldest parts of the current stack is copied to the heap and a fresh stack is introduced. When the stack underflows the saved stack is reinstated. [At least this is a rough idea of how it works - implementation details differ to make it process efficient.]
This means that you can rely on recursive solutions even when the recursive call occurs in a non-tail context.
This idea (no stack overflows) could be used in more traditional languages too. As you write in traditional languages there is a real risk to bump into the stack limit.