views:

1461

answers:

4

Background

I have an application written in native C++ over the course of several years that is around 60 KLOC. There are many many functions and classes that are dead (probably 10-15% like the similar Unix based question below asked). We recently began doing unit testing on all new code and applying it to modified code whenever possible. However, I would make a SWAG that we have less than 5% test coverage at the present moment.

Assumptions/Constraints

The method and/or tools must support:

  • Native (i.e. unmanaged) C++
  • Windows XP
  • Visual Studio 2005
  • Must not require user supplied test cases for coverage. (e.g. can't depend on unit tests to generate code coverage)

If the methods support more than these requirements, then great.

NOTE: We currently use the Professional edition of Visual Studio 2005, not the Team System. Therefore, using Team System might be a valid suggestion (I don't know, I've never used it) however I'm hoping it is not the only solution.

Why using unit tests for code coverage is problematic

I believe that it is impossible for a generic tool to find all the dead (e.g. unreachable code) in any arbitrary application with zero false positives (I think this would be equivalent to the Halting problem). However, I also believe it is possible for a generic tool to find many types of dead code that are highly probable to in fact be dead, like classes or functions which are never reference in the code by anything else.

By using unit tests to provide this coverage, you no longer using a generic algorithm and are thus increasing both the percentage of dead code you can detect and the probability that any hits are not false positives. Conversely, using unit tests could result in false negatives since the unit tests themselves might be the only thing exercising a given piece of code. Ideally, I would have regression testing that exercises all externally available methods, APIs, user controls, etc. which would serve as a baseline measurement of code coverage analysis to rule out certain methods from being false positives. Sadly however, I do not have this automated testing at the present time.

Since I have such a large code base with such a low test case coverage percentage however, I'm looking for something that could help without requiring huge amounts of time invested in writing test cases.

Question

How do you go about detecting dead code in an automated or semi-automated fashion in a native C++ application on the Windows platform with the Visual Studio 2005 development environment?

See Also

Dead code detection in legacy C/C++ project I want tell the VC++ Compiler to compile all code. Can it be done?

+1  A: 

We use Bullseye, and I can recommend it. It doesn't need to be run from a unit test environment, although that's what we do.

Alastair
Thanks for the suggestion. I'm going to investigate this option a bit further.
Burly
A: 

Use a code coverage tool against your unit test suite.

EvilTeach
This is exactly what I said is not an option. With such a low unit test coverage of 5%, using them for code coverage testing would result in massive numbers of false positives.
Burly
You have 5% coverage in your unit test suite, and your concern is about removing code that isn't used, rather than the code that is used. Interesting.
EvilTeach
You might consider upping your warning levels so the compiler reports unused code, and setting your linker options to not link in dead code.
EvilTeach
Dead code isn't my only concern, however removing it makes numerous maintenance tasks easier, including adding tests to code that IS in use as we refactor. Having dead code sprinkled about creates confusion for all, especially developers new to the project.
Burly
+1  A: 

Most Code coverage tools are a good idea. However obscure indirection, for example data-driven function pointers, or nightmarishly-badly-formatted spaghetti-code may easily fool many coverage tools.

Alternatively, consider "Memory Debugging" tools such as BoundsChecker, Purify and Valgrind. I've used them for many years for exactly the reason you describe. Most require little configuration, sometimes only a change in the link step.

I once used BoundsChecker in a production environment, running the application for weeks to build a report of what WAS being used; from which it was easy to determine what wasn't being used.

belwood
I agree belwood, false positives and negatives can certainly occur. However, if a tool can at least reduce the problem space for me, that would be great help. Valgrind is Unix only but I was already looking into the DevPartner tool for performance. Perhaps it's BoundChecker can help me as well!
Burly
+3  A: 

Ask the linker to remove unreferenced objects (/OPT:REF). If you use function-level linking, and verbose linker output, the linker output will list every function it can prove is unused. This list may be far from complete, but you already have the tools needed.

MSalters