Oh! It's so easy. I can't believe I didn't think to do that before.
... but every time I do find a bug, I am surprised to find it. Thus it stands to reason there are bugs I have not yet found. How do I find all of them?
Ah, well you seemed most concerned about the sheer quantity of foot-shot-off type bugs you put in, so I thought I'd put your mind at rest about that first. Sadly, that part is inevitable.
As for finding them before anybody else does, I suggest all of the following, which is what I do, because I've found it to work for me:
* Never run outside debugger unless you have previously verified inside the debugger that the run will work - this ensures that you are in a position to fully investigate any problems that might occur. (Some programs can't be verified ahead of time, because they're non-deterministic. (Hopefully due to non-deterministic sources of input, rather than anything in the code!) You just never run these outside the debugger.)
* Never run optimised build if you can help it (this is what the QA department and your users are for :) - again, this ensures you are in a good position to investigate any issues you discover. (Note - you should feel confident about using the debugger with an optimised build, most likely using the disassembly view, but I figure life is too short to be doing this all the time.)
* assert, lots, about everything, particularly pointers into buffers and indexes into arrays.
* -Wall, -W4, -Whatever
* Investigate memory manager's maximally-anally-retentive mode. If it doesn't have one, find a memory manager that does, and use that one instead. Switch it on and fix every complaint it might have.
* Find every debug option and #define for every library you use, and switch all of them on.
* Try to avoid having any multithreading.
* Make sure you know as many dark corners of the language as possible, and commit them to memory, so that you'll be able to spot them when people start making use of them accidentally.
* Add in some kind of crash dump/stack trace/etc. display to your program, so if it should crash during actual use then you stand some chance of getting some useful information back. (Avoid frame pointer omission for this reason.)
Unfortunately I can't guarantee that this will necessarily work, but I've found the above to at least have helped me minimise the sort of creepy, freakish bugs that you only get in C and its ilk.
Do you have a piece of code you feel confident about, such that you'd be able to say "here is an existence proof of carefully-written resilient C code of some significant length"? I'd like to take you up on an offer to validate that proof.
I do, but it's unfortunately internal at work. Everything I write for fun has so many library dependencies that you just have to cross your fingers and hope that it will all work as documented :)
... but every time I do find a bug, I am surprised to find it. Thus it stands to reason there are bugs I have not yet found. How do I find all of them?