4

I've got an enum type defined in the private section of my class. I have a member of this type defined as well. When I try to initialize this member in the constructor body, I get memory corruption problems at run-time. When I initialize it through an initialization list in the same constructor instead, I do not get memory corruption problems. Am I doing something wrong?

I'll simplify the code, and if it is a GCC bug I'm sure that it's a combination of the specific classes I'm combining/inheriting/etc., but I promise that this captures the essence of the problem. Nothing uses this member variable before it is initialized, and nothing uses the newly created object until after it is fully constructed. The initialization of this member is indeed the first thing I do in the body, and when the memory corruption happens, valgrind says it is on the line where I initialize the variable. Valgrind says that it is an invalid write of size 4.

Pertinent header code:


private:  
  enum StateOption{original = 0, blindside};    
  StateOption currentState;

pertinent .cpp code (causes memory corruption and crash):


MyClass::MyClass(AClass* classPtr) : 
  BaseClass(std::string("some_setting"),classPtr)
{
  currentState = original;
  ...
}

pertinent .cpp code (does not cause memory corruption and crash):


MyClass::MyClass(AClass* classPtr) : 
  BaseClass(std::string("some_setting"),classPtr),
  currentState(original)
{
  ...
}
  

edit: see my "answer" for what was causing this. After reading it, can anybody explain to me why it made a difference? I didn't change anything in the header, and obviously the object file was being rebuilt because of my print statements appearing when I put them in and the lack of seeing the bug under one build but not the other?

For a good explanation, I'll mark it as the answer to this question.

San Jacinto
  • 8,774
  • 5
  • 43
  • 58
  • When you say "nothing uses this member variable before it is initialized", are you sure that includes other elements in the initialisation list, even indirectly? Is there anything else called `original`? – Oliver Charlesworth Oct 22 '10 at 13:48
  • Does it work if you remove `private:`? – Marcelo Cantos Oct 22 '10 at 13:51
  • @Oil yes, I am positive. The base class does not implement anything like this functionality, and this class is the last one on the inheritance hierarcy (which is only two classes deep). The word "original" doesn't even appear in either the .h or the .cpp of the base class. Thank you for checking for a brain-dead mistake, though. I've made similar ones before :) – San Jacinto Oct 22 '10 at 13:53
  • Have you tried reducing the code until you have located the difference between a working and non-working version? – Zan Lynx Oct 22 '10 at 13:54
  • @oil also, the initialization list is actually pretty much the same as the real one in my code. Different names of things, but that's all I changed. – San Jacinto Oct 22 '10 at 13:55
  • Is it only failing when you execute it under valgrind, or does it also crash when the application is executed without valgrind? – Bart van Ingen Schenau Oct 22 '10 at 14:00
  • @Bart I don't get a hard-stop either way. I get a "glibc detected" followed by an awkward hang without valgrind and what I said previously when using valgrind. – San Jacinto Oct 22 '10 at 14:03
  • You've already tried minimizing the test case, but could you make it something we can compile ourselves? http://delta.tigris.org/ may help. – ephemient Oct 22 '10 at 14:03
  • Have you tried adding another member, int for instance, or replacing the enum by int? Maybe it's your base constructor that's going out of bounds, and valgrind gets it only in the second case. – jv42 Oct 22 '10 at 14:03
  • @Marcelo it exhibits the same behavior. – San Jacinto Oct 22 '10 at 14:04
  • @jv42 the base constructor is used in about 15 other classes. They don't show the same problem. I do have other members in this class that seem to be initialized fine. – San Jacinto Oct 22 '10 at 14:06
  • ..and if I put print statements before and after the initialization line in the body, the problem disappears until I take them back out... – San Jacinto Oct 22 '10 at 14:08
  • Provide a real testcase. The code above does not provide enough context to diagnose this. – wilx Oct 22 '10 at 14:08
  • @wilx I'm not sure what to tell you. This is my exact code, with names changed. You aren't seeing other member declarations from the header, but as far as execution of the constructor goes, you're seeing EXACTLY what my code has, in the real order that it appears, but with different names. The functionality in question does not appear in the base class at all. – San Jacinto Oct 22 '10 at 14:13
  • I agree with wilx: Not enough here. We don't have a definition for BaseClass. Plus, I tossed some similar code into G++ and it does not crash or do anything wrong. The question also needs the compiler version. – Zan Lynx Oct 22 '10 at 14:15
  • Have you set some fancy setting about enum sizes for gcc? – jv42 Oct 22 '10 at 14:17
  • Please provide a minimal, complete, compilable, example that shows the erroneous behaviour. That way, some of us can play around with it to understand better what is happening. – Bart van Ingen Schenau Oct 22 '10 at 14:18
  • Well, I decided to manually delete the object files rather than letting the make script do it, and when I rebuilt, it worked for the initializtion-in-body. ...Im think I need to go debug a make script now. Thank you, all of you, for giving me input and trying to help with this. – San Jacinto Oct 22 '10 at 14:19

1 Answers1

1

For posterity:

It appears as though the make script isn't pickup up the changes to these files for some reason. Manually deleting the objects rather than letting our "clean" target in the makefile caused a full rebuild (which took some time), and the problem disappeared.

San Jacinto
  • 8,774
  • 5
  • 43
  • 58
  • This reason might be that you modified Makefile – mip Oct 22 '10 at 14:31
  • Adding ccache ( http://ccache.samba.org/ ) will vastly shorten the recompilation time. – Mr.Ree Oct 22 '10 at 23:40
  • The most common reason for this is that the Makefile doesn't express the dependencies between object files and header files, so changing the header fails to recompile all the code that depends on it. – Marcelo Cantos Oct 22 '10 at 23:54