3

According to this question, Visual C++ 2005 (and also 2008/2010) does not zero initialize correctly data members.

Since I have a code which requires the standard behaviour, and which crashes in release mode (and not in debug), I suspect the issue comes from here.

Now, the problem is that the code base is quite large, and manually inspecting classes is difficult.

Is there a compiler option to trigger a warning on this non standard behaviour of MSVC ? With /W4, you get the warnings about some non standard extensions (conversions from rvalues to references, missing typename keyword), but not for this particular problem.

EDIT: I suspect code like that to cause trouble (pasted from the linked question)

include <cassert>

struct B { ~B(); Foo* m; };

int main()
{
   B * b= new B();
   assert ( b->m ==0);
}

in other portions of the code I have things like

B* b = new B();

and then, later,

if (b->m) { b->m->bar(); }

and b->m should be zero per the standard, but it's likely not (except in debug mode). I would like to detect such code (like a warning "m used without being initialized" or something)

Community
  • 1
  • 1
Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
  • The compiler is just as broken in the debug as in the release config. – Hans Passant Jan 06 '11 at 12:03
  • @Hans: some things are initialized to zero in debug mode and not in release (I don't know exactly which things), I had this problem once, and I suspect it is something like that. – Alexandre C. Jan 06 '11 at 12:09
  • @Alexandre: Generally if the compiler believes that something *should* be uninitialised, when in debug mode it will initialise it to some strange, likely-to-be-invalid value like 0x55555555. I would be surprised if debug mode initialised something to 0 in this case. – j_random_hacker Jan 06 '11 at 12:13
  • @@j_random_hacker: The VC debug RTL will zero out any memory before handing it to the application. The release RTL won't. – sbi Jan 06 '11 at 12:27
  • @sbi, @Alexandre: Way back in VS 6.0 at least, uninitialised locals in "debug mode" were set to 0xCCCCCCCC, with various flavours of dynamically allocated memory getting different patterns: http://msdn.microsoft.com/en-us/library/aa260966%28v=vs.60%29.aspx. This behaviour for uninitialised locals is turned on with `/RTCs` in later versions: http://msdn.microsoft.com/en-us/library/8wtf2dfz%28v=vs.80%29.aspx (a short sample program on VS2010 shows the value `0xCCCCCCCC` is used), and the debug heap patterns are still the same: http://msdn.microsoft.com/en-us/library/bebs9zyz%28v=VS.80%29.aspx – j_random_hacker Jan 06 '11 at 13:34
  • @j_random_hacker: I tried disabling optimizations and using /RTC options with no success. – Alexandre C. Jan 06 '11 at 13:36
  • @Alexandre: My suggestion would be to confirm that those switches are working as intended with a short sample program -- if that gives `0xCCCCCCCC`, then most likely the crashes you see stem from some other cause. `/RTCu` could be of use too. – j_random_hacker Jan 06 '11 at 14:05
  • @j_random_hacker: I think you're right with that, I remember seeing `oxCCCCCCCC`a lot when debugging in VC. I just never had to find any memory issues, so I never paid any attention to these features. – sbi Jan 06 '11 at 20:30
  • `0xcd` is also used by the debug heap for uninitialized heap-allocated memory. – James McNellis Jan 06 '11 at 22:46

4 Answers4

2

Is this about foo::foo () : member () { }? Paste some example (code) of the problem you are seeing. In standard C++ implementation, the member should have value 0 (assuming it is of a fundamental type). However some older compilers do not do/implement this correctly and just leave it uninitialized. AFAIK there is no warning for this. You will have to go through the code and initialize the member with 0 or other value explicitly.

wilx
  • 17,697
  • 6
  • 59
  • 114
  • I'm currently diagnosing the problem. As I told, the code base is quite huge, and I suspect that some pointers should be zero and they are not (I get access violation exceptions in release mode). I know that I default initialize pointers in code I wrote. – Alexandre C. Jan 06 '11 at 11:58
1

asper charles comment below, the compiler should be zero init before the ctor is called.

8.5 An object whose initializer is an empty set of parentheses, i.e., (), shall be
value-initialized. ... Value-initialization for such a class object may be implemented 
by zero-initializing the object and then calling the default constructor

12.1/7 A non-user-provided default constructor for a class ... performs the set of  
initializations of the class that would be performed by a user-written default 
constructor for that class with no ctor-initializer (12.6.2) and an empty
compound-statement.

12.6/4  If a given non-static data member or base class is not named by ... in 
initialiser   list ... the entity is not initialized. 

however, remember effective C++, if you declare a dtor then you should also declare a copy ctor, ctor and self-assignment (even if you declare as private)

dancl
  • 689
  • 5
  • 13
  • The `m` pointer on the sample code is legacy code I did not write myself (that's what I'm trying to debug). However, the `b` is a `boost::shared_ptr`. – Alexandre C. Jan 06 '11 at 12:16
  • 1
    This describes what a non-user-provided default constructor _would_ do, however `new B()` _value-initializes_ the new object, it doesn't use a non-user-defined default constructor. See 8.5 [dcl.init]. – CB Bailey Jan 06 '11 at 12:19
  • 1
    The rule of _three_ is a guideline and doesn't include the default constructor. Whether you should provide a default constructor is usually a separate concern although often when you provide 'the three' you want at least one user-declared constructor other than just the copy constructor, default or otherwise. – CB Bailey Jan 06 '11 at 12:56
  • BTW, what version of the standard are you using? In _value-initialization_ for an object of class type with no user-declared default constructor, *no* constructor is called. Also where does this come from? "Value-initialization for such a class object may be implemented by zero-initializing the object and then calling the default constructor" – CB Bailey Jan 06 '11 at 13:01
1

Don't work around it, attack it directly.

You'll need a C++ parser. Using the parser you'll have to track the types of variables which have no been properly assigned within each constructor of the classes. Once you've got that going it's simply a matter of inserting the proper syntax to make initialization happen in a desirable way. It's not a simple script to write but it'll save you loads of headache later.

FIrst step is just getting output from the parse tree to label problems for you:

class Foo{
public:

    Foo(int a) : mA(a){}

private:

    int mA, mB;
};

you'll want your script producing messages like: In class Foo :: missing initializer mB

Then get brave and transform that output into an instruction set to traverse the parse tree and insert missing items so that your code looks like:

class Foo{
public:
    Foo(int a) : mA(a), mB(0){}

private:

    int mA, mB;
};

So my best advice is to not try to work around the issue, attack it directly. If you still have problems after that, grab your nearest static code analyzer and memory analyzer. Those are the tools that will help you best of all.

wheaties
  • 35,646
  • 15
  • 94
  • 131
0

Are you sure you (the people purportedly citing the ISO C++ Standard) are actually citing it? And not being confused with the text for updated versions specified in TR's which are not actually Standards? Or C++11 which probably will be soon, but one can hardly expect MS to conform to something not yet officially a Standard.

Yttrill
  • 4,725
  • 1
  • 20
  • 29