Few takeaways from that time: inter procedural matters: if your function reallocated a pointer passed as an argument, you want to treat it as ‘free’ regarding this argument, and conversely, if your function returns a newly allocated memory, you want to mark it as such, and so on. There is also a trade off between the breadth of the analysis and the human ability to comprehend it, author mentions 110 node path in the article.
The subject of my unfinished PhD thesis and something I hope also picks up is the combination of static and dynamic analysis, used iteratively. If your static analysis flags a suspicious path but does not have the means to figure out if it is true or not, instrument it and leave it to the dynamic analysis to run through it (the idea here that total instrumentation a la valgrind is detrimental to performance so you will get some gain from selective instrumentation). Conversely, dynamic analysis may provide some hints as to where static analysis should be applied at a greater depth and provide automatic annotation of functions with regard to their behaviour and - possibly - invariants, that help with the state explosion.