2

I need a static analyzer that will find uninitialized variables members/variables... of a templated class type.

Can any analyzer do this? I tried clang/cppcheck and a couple of others with no luck.

Here is my test code:

enum class ViewMode
{
 One   = 1,
 Two     = 2,
 Three  = 3,
 Four     = 4
};

class TestClass {
 public:
   TestClass() {}
};

template<typename T, bool C = std::is_copy_constructible<T>::value>
class TemplateTest
{
 public:

  TemplateTest() {}

  TemplateTest(const T& value)
   : value_(value)
  {}

  TemplateTest(const TemplateTest&) = delete;

  TemplateTest(TemplateTest<T, C>&& rhs)
      : value_(std::move(rhs.value_))
  {}

  TemplateTest(T&& value)
      : value_(std::move(value))
  {}
 private:
  T value_;

};

class StaticAnalysisTest {

 public:
  StaticAnalysisTest() {}

  void DoSomething() {

  }

 private:
  ViewMode viewMode_;     //this uninitialized warning is found
  TemplateTest<ViewMode> viewMode2_; //this one is not
};

I have further distilled the problem to:

class Foo
{
 private:
  int m_nValue;
 public:
  Foo() {};
  Foo(int value) : m_nValue(value) {}
  int GetValue() { return m_nValue; }
};

class Bar
{
 public:
  Bar(){}

  void DoSomething() {
    Foo foo;
  }
};

This does not generate an unitialized variable warning, but when I comment out:

 //Foo(int value) : m_nValue(value) {}

it does

cierech
  • 383
  • 4
  • 14
  • 1
    `TemplateTest` doesn't even have a default constructor, so your code doesn't compile. – Rakete1111 Aug 09 '17 at 13:39
  • Sorry, modified code to compile. – cierech Aug 09 '17 at 17:10
  • 1
    Unitialized at what point in time? After the constructor runs and before anything else happens to the object? If there are multiple constructors, and some initialize one slot, and some initialize other slots, but all slots are covered by the set of constructors, is that "uninitialized" by your definition? Or do you want to know if a slot is uninitiaized after the constructor is called from a specific site? – Ira Baxter Aug 09 '17 at 21:20
  • I guess what is problematic, and I would like to find out by static analysis, is the situation that the object construction by using one of the constructors provided does not initialize the value_ member. Does that make sense? – cierech Aug 10 '17 at 02:05
  • So in my example, by using the default constructor of TemplateTest in: TemplateTest viewMode2_; TemplateTest::value_ does not get set which is something I was hoping to catch with static analysis. – cierech Aug 10 '17 at 02:30
  • So what you want to know is if every constructor initializes every member. What if the constructor passes a reference to a member, to a function defined as external? That function may or may not modify the member. Count that as "initialized" (optimistic) or "uninitialized" (conservative)? What if it invokes a method supplied by the templated class (essentially the same problem)? – Ira Baxter Aug 10 '17 at 17:12
  • Right, in that case I would expect no warning, since the analyzer can't be sure. But in the simplified case I supplied, that's not the case right? The analyzer does know. So is the answer that this is by design, and no analyzer can generate a warning in this situation? – cierech Aug 10 '17 at 17:59
  • I suppose you want the answer off-the-shelf. I don't have that, but can point to a tool that I think could give you the answer with some configuration effort. – Ira Baxter Aug 10 '17 at 20:24
  • I tried cppcheck and clang with all warnings turned off, and they didnt report this error... So my original question was is there a static analyzer that would detect this, or is this case ambiguous and is just something analyzers dont look for. – cierech Aug 10 '17 at 20:44
  • I meant all warnings options turned on of course :) – cierech Aug 11 '17 at 00:59
  • If the off-the-shelf tools don't look for this, then they don't look for it. In that case you may want to turn to a customizable tool, from which this information can be extracted. I don't know if Clang can be bent to do this. A tool I do know can be customized for this: see https://stackoverflow.com/a/8818844/120163 – Ira Baxter Aug 11 '17 at 11:41

1 Answers1

2

Thank you for evaluating Cppcheck. A warning is given for the second example, in case you add the --inconclusive flag, for example:

class Foo
{
private:
    int m_nValue;
public:
    Foo() {};
    explicit Foo(int value) : m_nValue(value) {}
    int GetValue() const
    {
        return m_nValue;
    }
};

class Bar
{
public:
    Bar() {}

    static void DoSomething() {
        Foo foo;
    }
};

The output from Cppcheck

$ cppcheck --enable=all --inconclusive uninitmembervar.cpp 
[uninitmembervar.cpp:6]: (warning, inconclusive) Member variable 'Foo::m_nValue' is not initialized in the constructor.
orbitcowboy
  • 1,438
  • 13
  • 25
  • Follow up question: Any idea, why this doesn't raise the unitialized value warning `template::value> class Observable { public: Observable() {} private: T value_; }; class Bah { public: Bah() {}; private: Observable tValue_; };` But when I remove the second template parameter (bool), it does? – cierech Aug 12 '17 at 23:13
  • It seems that you have found a case, where Cppcheck is currently blind. I have created a ticket about this test case on our bugtracker (http://trac.cppcheck.net/ticket/8162#ticket). Many thanks for evaluating Cppcheck! – orbitcowboy Aug 13 '17 at 09:08