If you code in C, Objective-C or C++ you can use the CLang Static Analyzer to critique your source without actually running it.
There are some memory debugging tools available: ValGrind, Guard Malloc on Mac OS X, Electric Fence on *NIX.
Some development environments provide the option to use a debugging memory allocator, that does stuff like fill newly allocated pages and newly freed pages with garbage, detect the freeing of unallocated pointers, and write some data before and after each heap block, with the debugger being called if the known pattern of that data ever changes.
Some guy on Slashdot said he got a lot of value out of single-stepping ever new line of source in a debugger. "That's it" he said. I don't always follow his advice, but when I have it has been very helpful to me. Even if you don't have a test case that stimulates an uncommon code path, you can twiddle a variable in your debugger to take such paths, say by allocating some memory, then using the debugger to set your new pointer to NULL instead of the memory address, then stepping through the allocation failure handler.
Use assertions - the assert() macro in C, C++ and Objective-C. If your language doesn't provide an assert function, write one yourself.
Use asserts liberally, then leave them in your code. I call assert() "The test that keeps on testing". I use them most commonly to check preconditions at the entry point of most of my functions. That's one part of "Programming by Contract", which is built into the Eiffel programming language. The other part is postconditions, that is, using assert() at function return points, but I find that I don't get as much mileage out of that as preconditions.
You can also use assert to check class invariants. While no class is strictly required to have any invariant at all, most sensibly designed classes do have them. A class invariant is some condition that is always true other than inside of member functions that might temporarily place your object into an inconsistent state. Such functions always must restore the consistency before they return.
Thus every member function could check the invariant upon entry and exit, and the class could define a function called CheckInvariant that any other code could call at any time.
Use a code coverage tool to check which lines of your source are actually getting tested, then design tests that stimulate the un-tested lines. For example you could check low memory handlers by running your app inside a VM that is configured with little physical memory, and either no swap file or a very small one.
(For some reason I was never privy to, while the BeOS could run without a swap file, it was highly unstable that way. Dominic Giampaolo, who wrote the BFS filesystem, urged me never to run the BeOS without swap. I don't see why that should matter, but it must have been some kind of implementation artifact.)
You should also test your code's response to I/O errors. Try storing all your files on a network share, then disconnect your network cable while your app has a high workload. Similarly disconnect the cable - or turn off your wireless - if you are communicating over a network.
Try killing your app with the debugger or with "kill -9" on *NIX while it is right in the middle of writing a big, important file. If your app is well-architected, the entire file will get written or will not be written at all, or maybe if it is only partially written, what does get written will not be corrupted, with what data that is saved being completely usable by the app upon re-reading the file.
databases always have fault-tolerant disk I/O, but hardly any other kind of app does. While journaled filesystems prevent filesystem corruption in the event of power failure or crashes, they don't do anything at all to prevent the corruption or loss of end-user data. That is the responsibility of the user applications, but hardly any other than databases implement fault-tolerance.