0

Consider this simple piece of code:

#include <iostream>
#include <sstream>

class Utl
{
public:

    // singleton accessor
    static Utl& GetInstance();

    virtual std::string GetHello( bool full ) = 0;
};

class UtlImpl : public Utl
{
public:
    UtlImpl() {}

    virtual std::string GetHello( bool full )
    {
        return (full)?"full":"partial";
    }
};

Utl& Utl::GetInstance()
{
    static UtlImpl instance;
    return instance;
}

int main( int argc, char* argv[] )
{
    std::cout << Utl::GetInstance().GetHello(true) << std::endl;  
    std::cout << Utl::GetInstance().GetHello(false) << std::endl;
    return 0;
}

I compile this with Visual Studio 2015 in "Debug" and "RelWithDebInfo" mode.

Then I use a coverage validation tool (Software verify - Coverage Validator).

For the Debug build, the tool reports a 100% coverage

For the RelWithDebInfo build, the tool reports a 66.67% coverage. It reports the function Utl::GetInstance() has not been executed.

As RelWithDebInfo is optimized, I suspect that's because the function has been inlined by the compiler (I'm not familiar with assembly code to verify that, but I can post anything that would help if someone explains me how to check this). But when I use Software verify's DbgHelp browser tool, this one reports that a Utl::GetInstance() is present in the binary.

Is it possible that Visual Studio inlined the code of Utl::GetInstance() function but also kept a "real" Utl::GetInstance() in the binary (then possibly ending with two implementations of this code)? That would explain why the tool reports me the function has never been called, while its code has definitely been executed...

jpo38
  • 20,821
  • 10
  • 70
  • 151
  • 1
    That definitely is possible. You would think it would be safe to discard but [apparently it depends on linker settings](http://stackoverflow.com/q/6215782/1277769) – SirGuy Dec 05 '16 at 14:28
  • Yeah, I repro this looking at the disassembly, with LTCG, /Gy, and /OPT:REF enabled. It's inlining the implementation of `Utl::GetInstance()` in the `main` function (although not the virtual function calls; MSVC never inlines those), but still generating code for a `GetInstance` function. I'm not sure I understand why this is an actual problem. Are you just curious about what's happening and why, or are you actually trying to figure out some way of removing the out-of-line code from the binary image? – Cody Gray - on strike Dec 05 '16 at 14:35
  • @CodyGray, I assume, it's a problem since verification tool is not reliable? – SergeyA Dec 05 '16 at 14:40
  • @CodyGray: I'm curious, but am also concerned... need to reach 100% (or at least 99.9%) code coverage on a project using unit test. Unit tests are too long to run in Debug mode, so we run them in RelWithDebInfo....but then we cannot reach 100% code coverage because those functions are still present in the binary while they cannot be actually called at runtime! – jpo38 Dec 05 '16 at 14:41
  • @jpo38, I am afraid, you won't be able to with the tool you are using. If it can't detect instances of inlining function, it's not going to help you. – SergeyA Dec 05 '16 at 14:43
  • Any function that has global scope needs to have a callable function. Maybe turn off inlining in MSVC just for the coverage test? – stark Dec 05 '16 at 14:45
  • @stark: Did set "Inline function expansion" to "Disabled (/Ob0)" and now I get a 100% coverage result. Thanks. Please post this as an answer to get deserved reputation! – jpo38 Dec 05 '16 at 14:48

1 Answers1

1

Any function that has global scope needs to have a callable function as well as the inlined function, so there will be duplicates.

Setting "Inline function expansion" to "Disabled (/Ob0)" when building allows OP to get 100% coverage for test.

stark
  • 12,615
  • 3
  • 33
  • 50