Exactly how return addresses and thrown exceptions interact is left to the details of how your particular compiler implements exception handling. To say anything about it with much certainty, someone here would have to be familiar with those internal details.
It's certainly conceivable that a buffer overrun could corrupt data that is only used by the exception handling (thus causing a throw to fail) while leaving the return address intact (thus allowing a normal return to succeed). But again, that depends on how your compiler is making use of the stack. (On a different compiler you might get totally different symptoms). It's also possible that the corruption has caused other problems that you simply haven't noticed yet. Or that such corruption will cause problems in the future after the next time you change your code. If the stack (or other memory that C++ depends on) becomes corrupted, then just about anything could happen.
Wither some educated guess-work or knowledge of the compiler details, I'm sure someone could eventually answer the specific questions about return addresses and how throwing works. However, I really think these are the wrong questions to be asking.
If you actually know you have a buffer overrun, then there's no point in trying to answer these questions. Just fix the overrun.
If you only suspect you have an overrun or are trying to track down how it's happening, then try stepping through your code in the debugger and watch for changes to memory outside the bounds of your variables. Or perhaps, alter your function to always throw and then start commenting out suspicious parts of your process one by one. Once the throw starts working again, you can then take a closer look at the code you last commented since the problem is most likely there. If these suggestions don't help, then I think the real question to ask here is "How do I track down memory corruption that only affects throwing an exception?".