Sign in to follow this  

*Very* strange behaviour with application compiled under Visual C++ 2008 Express

This topic is 2663 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 know that usually noobies who desparately need help overreact in subject topics but I assure you I don't have a nooby problem :).
So, I've a game I'm writing with lots of classes and so on. One day I decided to add additional variable to some class. I compiled it and... hmm... To put this straight I'll enumerate the "combinations":
- game run in Debug mode *through* Visual Studio (by pressing F5) - everything works
- game run in Release mode *through* Visual Studio (by pressing F5) - everything works
- game run in Debug mode by running the exe file by hand - everything works
- game run in Release mode by running the exe file by hand - *problem!*
The problem is that from time to time some specific function (the same all the time) is being called. I would check the call stack but I simply can't - the problem doesn't appear neither in Debug mode nor when game is ruh through VS.
So the problem appears only if I declare some variable in the class. That's the only difference between working and non-working version.
So, who to blame? Me because of some horrible bug in the code? The compiler becauses it messes something up when the class is bigger in few bytes? Or maybe some Windows's DLL that's get loaded when running the game outside VS? I simply have no idea.
I can only add that my friend compiled the game under Linux and didn't observe the problem.

Share this post


Link to post
Share on other sites
You probably have an uninitialized data problem, or a buffer overrun.

Running from VS, or a file linked against the debug libs, will generally get you the debug heap, which has a number of quirks that hide those sort of things. Running release outside of visual studio doesn't.

Share this post


Link to post
Share on other sites
Since you did not specify, I am assuming here you are working on a native Visual Studio C/C++ application.

Quote:
Original post by maxest
One day I decided to add additional variable to some class. I compiled it and... hmm...

The first thing: do a full rebuild of the project to confirm that VS incremental rebuild was not messed up. If you have done any funny stuff to your solution/project build configurations, check that Clean all actually succeeds in cleaning up everything before proceeding. (nothing more fun than finding bad paths and images not getting updated with new version at all due to it)

Quote:
Original post by maxest
- game run in Debug mode *through* Visual Studio (by pressing F5) - everything works
- game run in Release mode *through* Visual Studio (by pressing F5) - everything works
- game run in Debug mode by running the exe file by hand - everything works
- game run in Release mode by running the exe file by hand - *problem!*


The most commonly I've seen this is in the context of thread race conditions. Running in the debugger would not exhibit the same run patterns as running outside the debugger, and in debug mode the thread code execution patterns hide the issue present in release mode. To debug these:

  • Write a crash handler that automatically produces a .dmp file. See for example msdn (a bit old, for VS 2005, but gives you more words and concepts to google for)
  • For .dmp, compile the release mode with debug mode program info database enabled, and with /Oy- to make most use of .dmp files.
    msdn
  • Add manual re-entrancy checks and debug mode lock guards to your code to find issues with lockless data sharing.

The second relates to bad memory use, as ReaperSMS already pointed out. To debug:

  • Write code to generate .dmp files, as above.
  • msdn . Particularly useful are the _CRTDBG_ALLOC_MEM_DF, _CRTDBG_DELAY_FREE_MEM_DF and CRTDBG_CHECK_ALWAYS_DF, but they make debugging your app run very slow. To find a middle ground, see msdn .
  • Make sure your runtime libraries match in all objects you are linking together.
  • Make sure all your code is compiled with the same #defines (minus those you know that can/should safely differ). Especially the CRT-altering ones, like _SECURE_SCL=x.
  • Try Visual Leak Detector. While it's mainly for detecting memory leaks, it can also make hidden memory-related crashes manifest themselves. vld .
  • Compile with /Oy-. Try disabling optimizations altogether in Release.
  • Force assert()s in into the release build as well.

Quote:
Original post by maxest
I would check the call stack but I simply can't - the problem doesn't appear neither in Debug mode nor when game is ruh through VS.

You can attach a debugger to a crashed process post-mortem, but you need to have the program database generated.

Share this post


Link to post
Share on other sites
So "run in Release mode by running the exe file by hand" and then attach the debugger. If the problem occurs too close to the start of the program, add a Sleep at the start to give you time to attach.

Found the bug now?

Share this post


Link to post
Share on other sites
Quote:

# Try Visual Leak Detector. While it's mainly for detecting memory leaks, it can also make hidden memory-related crashes manifest themselves. vld .

I've tried. It showed nothing. The application doesn't have any kind of memory leaking

Quote:

# Compile with /Oy-. Try disabling optimizations altogether in Release.

I've used /Od and... it works. The problem doesn't occur. What can that mean in this context?

Share this post


Link to post
Share on other sites
Quote:

I've used /Od and... it works. The problem doesn't occur. What can that mean in this context?


It means that when you use /Od it works and the problem does not occur. Don't use /Od then, but build with such optimization flags that will show the problem, and continue debugging the crash with other means.

Share this post


Link to post
Share on other sites
I've tried attaching the debugger to my application and although the function is still being called (the one that shouldn't), the debugger doesn't expose any kind of crash.

Moreover, I simply changed linking from Multi-threaded to Multi-threaded DLL and the problem no more appears. However, since it causes the output exe file to be smaller, the data arrangement in it must differ so this "bad pointer" or something can probably be doing something else (calling some other function) that I can't see immediately.
Just to be sure.. after I had attached the process to the debugger and put some breakpoint to the function that is being called, the debugger indeed stopped in this place and gave me a call stack. But unfortunately I don't have an insight into the values of all the variables. And yes, I have a Program Debug Database generated for the Release. Yet they're smaller than those from the Debug version. Some magic switch should I make in the options?

This may also be something with the "thread race" you mentioned. The code is indeed multithreaded so I shall check these .dmp files.

[Edited by - maxest on August 29, 2010 10:45:51 AM]

Share this post


Link to post
Share on other sites
Well, in fact yesterday I did a "binary search" in the project's repository and found the one from which adding this variable to the class causes problems. However, the change was very subtle so I'm not sure whether this could be the problem. But I will do fruther investigation of course and let you know.

Share this post


Link to post
Share on other sites
Adding a variable to a class will only cause bugs if you're doing something like not initializing your members correctly, or doing unsafe casts between classes. So whatever the problem is, it's likely much deeper in your code than just having a variable someplace.

Share this post


Link to post
Share on other sites
Quote:
Original post by maxest
Just to be sure.. after I had attached the process to the debugger and put some breakpoint to the function that is being called, the debugger indeed stopped in this place and gave me a call stack. But unfortunately I don't have an insight into the values of all the variables.

Did you try checking the disassembly? If you can find where the assembly does the actual function call you might be able to trace where it gets the address from.

Share this post


Link to post
Share on other sites
I've got some news. Since my computer was running annoyingly slowly I made a format. I've installed 32-bit Windows 7 (I had Windows XP 32-bit running before) and the same Visual C++ 2008 along with the same libraries that my game needs. And after running the version of my game compiled before the format, I saw no more this particular function calling. Eveything works fine. On the same exe file. So could this be some problem with Windows libraries or something? A few days back I also encountered some "critical" error during linking my game via VC 2008. Could this somehow influence the game?

Share this post


Link to post
Share on other sites
Here's the way I see this. I hope you feel this helpful and giving another perspective, rather than being patronizing by stating the obvious. I might be reading too much into your reply, in which case ignore the edge of it.

In your first post you said you can deterministically reproduce your code calling a function you did not intend to, but only when running on release mode, and outside the debugger. When fighting a bug, deterministic reproducability is the best thing you can hope for. Do not ever let go of it!

The fact that you witnessed the exact same issue again and again, even when you rebuilt the code from scratch, strongly signals that there was a real issue.

That it happened only on release and not on debug is most often a result of misconfiguration on linker options (mixing CRT libs, preprocessor settings mismatch, incompatible configuration of libs and dlls in 3rd party dependencies) or a race condition, as you say your code is multithreaded and that /Od flag hid the problem.

Another improbable reason one could think of is that your computer had a virus, which caused that rare sequence of events to occur. Or that an antivirus scanner, DRM protection driver, or software X gave a conflict. But of course, establishing these kinds of hypotheses is useless now, since you cannot and prove them right or wrong anymore.

Among others, you offered the following hypotheses for the cause of the fault:
- the compiler produces faulty code if the size of a certain class is too big.
- some unknown windows DLL gets loaded and executed, which results in bad code.
- It is a bug in windows since in linux it works fine. Or WinXp, since Win7 does not show the problem.

From the above, the first one is completely implausible, but if correct, provable, and reducible to a small test case that showcases the problem. The second one should be profileable, and the third one traceable back to a windows subsystem. Making any hypothesis is only useful if you act on it - otherwise it is just random guessing that will not lead to progress.

These hypotheses all have in common that they make grand assumptions that it is the environment at fault, big time, instead of your own code. This can happen, but since one should look at the most probable causes first, I assume you already double- and triple-checked your code to be error-free by ruling out all the possible causes?

Trying a re-format can be a good last-try effort, but if you did not store a clone of your HDD contents beforehand, you threw away a gold nugget, because you closed your window of opportunity of being able to deterministically reproduce the problem. It is the equivalent of having ran away from the bug instead of fixing it.

Sometimes that might be the best possible thing to do, given the circumstances. But you should feel awful having to do so. If you now think that the problem is solved, you are accepting that hiding a bug is a form of fixing them. Programmers who think like this fall easily to superstition when it comes to fixing those nasty mysterious bugs.

Why I am reasoning like this is that it looks like you are asking the community to judge whether your system re-format proved that there was a bug in WinXp that's fixed in Win7 that caused the problem. Maybe, but would you really take a random poster's guess "yeah, sounds like it." as a satisfactory confirmation for it, one that would give you the closure you are looking for?

Yeah, thought not. Rather, I would only feel content if I could have proven with a small snippet that the compiler produces wrong code, or that uninstalling antivirus fixed it, or that the xxxyyy.drv calls back on a wrong function pointer when it never should.

Now the best you can do is to hope that the reason really was specific to your old setup and that you will never see the issue again. Unfortunately, someone else might have just the same setup than you did, or it might happen that next week the same problem causes a different kind of symptom on the next machine you run your game on, but only once every 10 runs, and only on Fridays, and it's the different symptom every time!

Let's just hope this is not the cause. Happy hunting!

Share this post


Link to post
Share on other sites
Quote:
Original post by clb
[snip]


Quote for emphasis.


IMHO you still have a bug - but now, you have a really hard to detect and fix bug, instead of a really easy to fix bug (which was easily reproduced).

Probably 80% of my debugging time is spent constructing reliable reproduction cases for bugs, so I can easily determine when they are fixed, and easily introduce things like automated testing and (in extreme cases) revise our coding standards to ensure these things don't happen again.


As clb eloquently put it, you threw out a gold nugget here.

Share this post


Link to post
Share on other sites

This topic is 2663 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this