@ Phil Rigby
"is it possible to prevent buffer overflows by changing the design of the hardware, say something on the cpu rather than in software?"
Yes, and it was done a good 50 years ago. The Burroughs (now Unisys) "Large Systems" have a stack-oriented, tagged-memory, architecture with descriptor-based memory references. The memory tags allow the hardware to distinguish code and data, code being read-only. The descriptors result in array references being boundary-checked by the hardware.
Rather like wearing a belt and suspenders ("braces" to UKoids): not only can you not overwrite code, you can't even run off the end of an array and overwrite other data.
I believe there have been other hardware designs with similar feature sets, thinking of Honeywell, GE, Philco, and Bendix. Don't have personal knowledge of those so I'll leave them to the cyber-historians.
However, on reflection, it isn't clear to me how resistant such an architecture would be to a determined attempt at subversion. A mainframe presents a totally different environment from a personal computer where the owner is also the sysop.