• Advertisement
Sign in to follow this  

Optimisation causing crashes?

This topic is 3489 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've never experienced this before: If I compile with O2, my program crashes. If I use O1 then everything is ok! I can't compile with both debug info and O2, so I'm not sure exactly how to deal with this... If I run with the debugger attached, I get this dialog: Microsoft Visual Studio C Runtime Library has detected a fatal error in test.exe. Press Break to debug the program or Continue to terminate the program. And I'm not sure if I should trust the call-stack, but it looks something like: ... std::vector::end() std::vector::push_back() NameIndex::NameIndex() ... And heres some code-snppets of the NameIndex class, and how I'm calling push_back:
	struct NameIndex
	{
		NameIndex( const char* n="", int i=0 ) : name(n), index(i) {}
		std::string name;
		int         index;
	};
....
std::vector<NameIndex> m_Vector
....
m_Vector.push_back( NameIndex(szName,index) );

Any ideas on how to diagnose my problem?

Share this post


Link to post
Share on other sites
Advertisement
i had the same problem some times. In both cases all I could do is disabling optimization at all. I think your std::vector doesn't cause the crash. it is bug of the compiler or linker. i'll be happy if i'm mistaking

Share this post


Link to post
Share on other sites
Does it all work fine in a debug build? What version of visual studio do you have (Don't say VC6...)? Does it work if you compile a debug build but with optimisations on? Do you have any secure STL stuff #define'd out?

Share this post


Link to post
Share on other sites
You could step into the assembly and compare what is going on.

You could also try turning off optimisation around specific parts of code using a #pragma to narrow it down.

Share this post


Link to post
Share on other sites
I also have the exact same problem with my raytracer code (http://sourceforge.net/projects/raywatch). I haven't solved it, I use -O1 optimization; -O2 and above causes it to crash. In my case, it was to do with a static std::map the object factory uses. If the static std::map is removed, it works fine.

It simply crashes when compiled with MinGW 3.4.5 (on Windows). However, the code works fine even with full optimizations (-O3) when compiled with GCC 4.1.3 (on my Ubuntu Linux box).

So, I'm guessing it's nothing wrong with the code; just a compiler bug, which hopefully will get fixed with future versions.

Share this post


Link to post
Share on other sites
A few things to keep in mind are that without optimizations, data structures and stacks are often padded to try to detect errors like buffer overruns. It's possible that you might be getting the padding and not have the error detection on. Additionally, optimizations are made with single-threaded code in mind and you need give some hints when these assumptions are not valid. So, if you're using multi-threaded code, you may not have given the compiler or linker enough information to make the correct optimization. Ultimately, it's rarely the fault of the optimizer for code breaking when optimizing. What I mean by this is when your code breaks under optimizations, it's usually because you had a bug in your code that happened to fly by without optimizations; it's not usually a bug in the optimizer.

Share this post


Link to post
Share on other sites
Thanks for all the replies.

Quote:
Original post by Evil Steve
Does it all work fine in a debug build? What version of visual studio do you have (Don't say VC6...)? Does it work if you compile a debug build but with optimisations on? Do you have any secure STL stuff #define'd out?
Yes. 2005 Pro. Yes. Not that I'm aware.
Quote:
Original post by Kylotan
You could step into the assembly and compare what is going on.
You could also try turning off optimisation around specific parts of code using a #pragma to narrow it down.
I'm not that proficient with assembly... I'll definately try some pragmas - I guess this is all I need to know?
Quote:
Original post by Zahlman
Where does szName come from?
It's actually from a std::string, like this:
m_Vector.push_back( NameIndex(strName.c_str(),index) );
I did this because in some other places NameIndex's are constructed from legacy code, but I could just make these other pieces of code construct a temporary std::string and throw out my use of char* entirely...
Quote:
Original post by Rydinare
Additionally, optimizations are made with single-threaded code in mind and you need give some hints when these assumptions are not valid. What I mean by this is when your code breaks under optimizations, it's usually because you had a bug in your code that happened to fly by without optimizations; it's not usually a bug in the optimizer.
This code is only run from one thread (other threads are used, but their outputs are buffered and retrieved by the main thread).
I hope it's a bug in my code (not the compiler), but I'm too dependent on debug builds for tracking down these kinds of bugs! :(

Share this post


Link to post
Share on other sites
It's possible, but not likely, that a bug in the optimizer
produces a crash.

It's much more likely that you have a bug which is being manifest
due to the perturbations of the optimizer. Padding of structures
and initialization of variables are good candidates. Another gotcha
is that the compiler is allowed to change the order of side effects,
but only does so when optimizing. Ie: f(a(),b()), a() might be
called either before or after b() at the compiler's pleasure. Another
one I saw recently was calling a library function with the wrong number
of arguments (due to an incorrect header file) worked fine in the debug
version but crashed in a release version. C is full of such pitfalls.

Share this post


Link to post
Share on other sites
Change const char *n in the constructor to const std::string &n, and don't use C strings unless some library gives you C strings (in which case, you'd want to wrap them in std::string ASAP before they get destroyed). You probably have some funky memory issues going on as Zahlman was onto.

Share this post


Link to post
Share on other sites
Ok, I'm still not entirely sure what the problem was (as I've inspected everything in debug mode, and everything seems peachy), but replacing all of my char* usage with std::string&'s seems to have fixed it... or at least swept it under the blanket.

As far as I can tell, the compiler must have been destructing a std::string object too early, turning one of my char*'s into a dangling pointer.

Thanks, all.

Share this post


Link to post
Share on other sites
You may have been stomping memory by writing beyond the bounds of one of your char* arrays (which is why switching to strings fixed it).

This would produce different results depending on what was being stomped (explaining why it only occured in certain configurations/platforms).

Share this post


Link to post
Share on other sites
Quote:
Original post by dashurc
You may have been stomping memory by writing beyond the bounds of one of your char* arrays (which is why switching to strings fixed it).
I wasn't writing to any char*'s though - I only read from them by assigning a string object to them. AFAIK, the rules of scope/destruction should mean that this code is valid.
Basically, I just changed code A to code B to fix my problem:
/*-= A =-*/
std::string str1 = "asdf";
{
const char* sz1 = str1.c_str();
std::string str2 = sz1;
}
/*-= B =-*/
std::string str1 = "asdf";
{
std::string str2 = str1;
}
Quote:
Original post by Naurava kulkuri
If optimisations are involved, it could be something that Raymond Chen explains in his blog post titled How can a program survive a corrupted stack?.
Thanks for the good read ;)

Share this post


Link to post
Share on other sites
Note that it is extremely rare for the compiler's optimizer to CAUSE a bug. It is very common for them to EXPOSE bugs.

The linker's optimizer is more likely to cause issues. The only consistent linker error I've seen is the linker finding functions that aren't being called directly or called by name, and the function is dead-stripped. Sometimes the linker won't realize a function needs to be linked in, or is otherwise too aggressive when figuring out what isn't necessary from libraries.


Common compiler-exposed issues include (some of these were mentioned above):

Very common in my experience:
* Uninitialized variables containing different values, or containing unspecified/implementation-defined contents. Generally can be caught by high warning level, or static analysis tools like lint.
* Seemingly "premature" destruction, generally due to improper use of pointers or improper expectations of object lifetimes. Can be difficult to track down.
* Assuming continuity and order of objects in memory. This is generally a buffer overrun. At best these are exposed as a crash. At worst it is a subtle and seemingly random memory corruption that only happens in release/final builds.
* Assuming an order of side effects (ie: i = v[i++]; is unspecified behavior). Some are caught as compiler warnings at high warning levels, others are not.
* Assuming a particular alignment without explicitly forcing it. Especially troublesome when member variables are not sorted by size. These are either very easy or very hard to track down. This is very common on embedded systems.

Less common:
* Assuming an order for unspecified order of initializations (when unintentionally mixing static and dynamic initialization). These are generally easy to diagnose if you are know what to look for. A co-worker was hit by this about two weeks ago.
* Reordering of elements that are in an unspecified order. This is especially difficult to track down when blocks of members are laid out differently, which can be allowed with duplicate access specifiers. I see this happen once or twice a year, generally in intern's code.
* Assumed sizes of implementation-defined unspecified variables that may be optimized smaller. Generally caught by the compiler at high warning levels.
* Assuming that pointer casts between potentially differently-aligned pointers are valid pointers. Not a big issue on PCs, but extremely important on consoles and embedded hardware. I see this frequently by junior team members.
* Performing certain comparisons of pointers to members and virtual members. Again, this isn't much of an issue on PCs, and they are rarely compared this way.
* Unintentionally relying on temporary copies' existence or lifetimes. This is generally caught by high warning levels.

In multithreaded code:
* Assuming atomic operations that really aren't
* Assuming a particular order of execution or data access outside a synchronization mechanism

There are many more bugs that the optimizer can expose, but those are the ones I can think of at 11:30 at night.

Share this post


Link to post
Share on other sites
Quote:
Original post by Hodgman
Ok, I'm still not entirely sure what the problem was (as I've inspected everything in debug mode, and everything seems peachy), but replacing all of my char* usage with std::string&'s seems to have fixed it... or at least swept it under the blanket.
Nope I was wrong...
It seemed to have gone away, but after a clean/rebuild it popped back up again!

This buggy code is contained in a static-library, which is used by a DLL.

I finally fixed the problem by moving the affected files out of the static-lib and directly into the DLL...

Share this post


Link to post
Share on other sites
I highly suspect that the problem I was facing is a compiler bug. I narrowed down the code causing the crash to a static std::map. The application would simply crash when compiled with -O2 and above optimizations with mingw (gcc) 3.4.5. However, with gcc 4.3 on my Ubuntu box, and MSVC, it used to work fine with even highest optimization settings (-O3). When I upgraded to mingw (gcc) 4.3 (alpha), the problem went away.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement