Separate code and data stacks
" why don't CPU manufacturers simply keep the data and code/return address stacks separate?" -- Graham
This actually isn't a bad idea. Some processor architectures (specifically, ones with a highly orthogonal instruction set such as the PDP-11, ARM, MIPS, 68000 and PowerPC families) could already support this without much effort. You just need to have two instructions; "put the contents of register Y into the address pointed to by register X and decrement register X" and "increment register Y and get the contents of the address pointed to by register Y into register X". Then use any two registers as a "data stack pointer" and "execution stack pointer" respectively. Obviously, you would need to keep the data stack at a lower address in memory than the execution stack so the former cannot grow into the latter.
It's still not perfect, because code could still deliberately modify the execution stack -- or directly alter the data stack pointer to point into the execution stack. But such code *wouldn't* be able to get itself executed by anything so trivial as a stack overflow.
As for why it's not done; well, I suppose that all dates back to the 8080 which had only one stack pointer, implemented as a simple up/down counter, and corresponding dedicated PUSH and POP instructions. The 8086 implemented the 8080 instruction set, and kept the single stack. Everything since then, all the way to the Core 2 Duo, has carried 8086 -- and therefore 8080 -- legacy baggage. We can't get away from the 80x86 instruction set as long as anyone has 80x86 binaries they need to run.
The fact remains that the BEST way to make sure code doesn't contain exploits is just never to run any software whose Source Code has not been audited by independent (i.e., not connected with the author) experts. Auditing of source code, possibly in conjunction with provision of patches for any bugs discovered, would seem to be a service which has Intrinsic Value (i.e., if you are a programmer, you could make money doing this for people).
Of course, this approach is somewhat incompatible with Microsoft's (and others') business model, where they keep the Source Code a jealously-guarded secret *even from the people who are using the software* ! They've been getting away with that for long enough now that most people don't even know what Source Code *is*, or why it's important to them. Access to Source Code is a prerequisite not only for auditing software for vulnerabilities (bear in mind that, for every dishonest hacker looking for something they can exploit, there are several honest hackers looking for the same problems with the intent to release a patch and cure them ..... it's a matter of definition that good guys outnumber bad guys), but also for adapting the software you use to suit the way you do business. Otherwise, you would have to adapt the way you do business to suit the software you use.