I just replace operator new and delete (and malloc and free) with my own memory manager. You can then inject data blocks at the front and back of the allocated memory and place a defined data block there. You can detect buffer overruns by validating they are unchanged (the typical term for this is 'sentinels'). You can also detect memory leaks easily, most of that functionality is removed in release or master builds for performance reasons, and it can becoime a fairly large module in itself depending how much functionality you want but it's the best way to track downn these issues that can occur in all levels of C++ programming.
n!