If you print from both main program and interrupts, or from multiple interrupts running with different priority levels, the Serial.print code is *not* safe to use. Usually it will work anyway, where data loss is usually the worst problem. Lockups or really bad problems are extremely rare. But if the interrupts happen at just the wrong moment while a main program or lower priority interrupt is doing Serial.print, you can get data loss when the interrupt changes variables that were in use by the main program. It's a known issue for that use case.
Many times I've considered trying to make it safe for interrupts and main program. But doing so could impose a pretty substantial interrupt blocking time on all uses. It's also a pretty low priority compared to so many other things...
However, the is safe to use Serial.print within interrupts if all the interrupts using it run at the same priority. It's also safe if the interrupt never occurs while the other uses are in progress.
There may also be issues for causes with large bidirectional data flow, where fast incoming data and high-latency reading by user code starves the rest of the USB stack for buffers.
Of course, something in your code could be causing trouble. A very common issue we see on this forum is a buffer overflow, like writing 1 place past the end of an array (usually due to a "<=" check which should have been "<"). Corrupting the memory causes problems later which appear to be unrelated bugs when other code runs needing that memory.
Could be other stuff too. Nobody can even begin to guess without seeing your code. But here's an informal list covering pretty much all the scenarios we usually see on this forum.