I use try/catch a lot in my project. They work fine under debug version but it seems the exceptions are not caught under release version. I am using VS2010. Thanks.
Printable View
I use try/catch a lot in my project. They work fine under debug version but it seems the exceptions are not caught under release version. I am using VS2010. Thanks.
Thanks for the info. :rolleyes:
Make sure exceptions are enabled in your project settings.
You could try fixing whatever is wrong.
Again, how do you know there are exceptions to be caught? If nothing is thrown, nothing gets caught. So where is your evidence that an exception was thrown and you didn't catch it?
A debug build (one where the _DEBUG preprocessor is set), produces a program that does all sorts of checks that do not exist in release builds. Add to that, a release build is optimized, meaning the code you see in the debugger doesn't match what is actually being executed. The code you claim throws an exception could have been optimized away. So there is no "same circumstance" as a debug build.
Also, what types of exceptions? Memory exceptions? Then you are hoping that the same buggyness in your debug build will exist in your release build to cause an exception to occur?
Regards,
Paul McKenzie
There is an access violation exception so that it causes the program crash. So that is why I am sure an exception is thrown but it is not handled under release version. In the source code I do have a handler for such exception but obviously the handler is never called under release version. If as you claimed, a release build is optimized, then I might expect an exception is thrown under debug version but not under release version, which is exactly opposite to what is happening to my project.
LarryChen, how do you know you have a access violation being thrown?
The point is, you don't. You haven't said anything to make me think you do anyway.
Debug and release builds will be vastly different, and not every out of bounds memory access will produce an exception.
Try this in both release and debug mode. I have a feeling you will get the exception in release mode that you were expecting.
Edit: Just for clarification. Your code should look like this:Code:*(int*)0 = 0; //This will produce a memory access violation
Works for me, and it should work for you too. Also, keep in mind that this is completely MSVC/Windows specific. This will not work on any other OS or compiler (maybe some other Windows compiler.)Code:__try
{
*(int*)0 = 0;
}
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
{
cout << "Access Violation!" << endl;
}
Sorry to revive a dead thread, but I had this same problem. Try Catch works under debug but not release for x64 compiler using VS2010. The issues seems to be that Try Catch aren't implemented if the compiler is set to optimize the code. Right click project->configuration properties->c/c++->Optimization->disabled under the Release Version should re-enable Try Catch stuff.
And the same thing applies to your situation as in the other -- let's see your code that you claim should throw an exception, as what you think is being executed may never be executed.
Optimizing code means that code is removed and moved around. So the code you think should be throwing an exception may not have even been called, used, or it could have been removed from the final executable.
Do you really think that a major compiler only has exception handling when the code is unoptimized? If that were the case, then there would be thousands of programmers reporting this issue.
Regards,
Paul McKenzie
My particular piece of code is to catch an error if the user passes a pointer to a class that isn't valid.
d is a custom class that is linked to an OpenCL device and has a bunch of stuff in it. For my test, d is a NULL pointer.
Debug and Release with optimization off runs fine, any optimization and try-catch doesn't work.Code:try{
d->GetContext();
}
catch(...){
return OPENCLV_DEVICE_NOT_FOUND;
}
return 0;
Austin
Accessing a member function using a NULL pointer doesn't guarantee any exception will be thrown. The only thing it does do is guarantee undefined behaviour, and undefined behaviour means that anything can happen.
Instead of that, why not yourself actually throw an exception instead of relying on things you don't know will throw. You will see that there is nothing wrong with the exception handling.
Regards,
Paul McKenzie
In addition, this type of check is pointless. I can pass you a pointer that is valid in terms of being in the program's address space, but invalid in terms of the context of the program.
What if I pass a pointer to dynamically allocated memory, delete the pointer, and pass to you that address again? How do you know that the internals of what pointer points to is trash? Maybe it isn't trash yet, but is waiting to be overwritten later by the heap?
Let the programmer who passed that illegal pointer to your function pay the price. There is no way for you to identify in all (probably most) cases if a pointer is valid or not.
The only way to circumvent this is for you to create the object in a factory, and you pass that pointer to the object to the caller as a "handle". Then if the caller passes the handle to you, you do a lookup to see if it was one of the handles that came from your factory. That is the only way to get anywhere close to checking for an "illegal" pointer.
Regards,
Paul McKenzie
Well, in this example I pass a NULL pointer, but the user might pass anything, I've no idea what the user is going to do. I can't check for all possible invalid combinations. If I pass a NULL pointer, call a Getter function to return a value of something from a NULL pointer, I don't understand how that can't possibly be an error. It clearly is when optimization is off, but when any optimization is on it doesn't catch it.
The MS compiler must see that I'm not using d->GetContext() for anything and decides to optimize this out. Even if I do something like:
try-catch still isn't thrown, the program does straight to return 0. So optimization must still be deciding not to execute the code in the try-catch loop. Yeah, the compiler knows better than me 99.9% of the time, but this seems like an error that should be thrown.Code:try{
cl_context f = d->GetContext();
}
catch(...){
return OPENCLV_DEVICE_NOT_FOUND;
}
return 0;
Argh!!! :) I'll just turn optimization off, 100% of the heavy lifting through OpenCL and I would rather do the error handling and reporting to shutdown OpenCL gracefully then let the programmer screw something up on an easily catchable accident such as a NULL pointer or invalid memory location.
This code is wrapped in a DLL and I can't control the object 100% of the time. Just was letting the first poster know he wasn't alone and how he might be able to solve the issue.
There is a big difference in being an error and an error that guarantees an exception is thrown.
I think you have the wrong idea about exception handling in C++. The only exceptions that are guaranteed to be thrown are:
1) Exceptions that you throw.
2) Exceptions that are guaranteed by the ANSI specification to throw (e.g. the vector::at() guarantees to throw on illegal bounds, operator new is guaranteed to throw on failure, dynamic_cast throws on an illegal reference, etc.)
3) Exceptions that are thrown by the third-party library that is being used.
4) SEH exceptions for Windows (if they are enabled).
In no other circumstance is an exception guaranteed to be thrown. The keyword you seem to be missing is thrown. Just because your code is dodgy or an error doesn't guarantee a throw to occur.
This would guarantee a throw:
If you wrote that, then you would make headway.Code:if ( user_did_something_stupid )
throw myException;
Regards,
Paul McKenzie
So what happens when those other accidents that you can't detect happen? You're users are going to expect that your function catches everything and it cannot do that.
Second, there are a myriad of examples of NULL pointers and accessing a member function through the NULL pointer and not crashing. Again, accessing a member using a NULL pointer is not a guaranteed throw. The only thing you can do is
No try/catch is needed there. Anything other than that is a waste of time, as you're going to totally miss pointers that have proper addresses within the program's address space but are illegal to use in the context of the program. Again, the case of the pointer value that was created with new, and then deleted, and then passed to your function. There is no way you will be able to know that the pointer value is illegal.Code:void someFunctin(T *ptr)
{
//...
if ( ptr )
{
// do work with ptr
}
else
{
// error -- here you can throw an exception back to caller
}
}
Last, it is the responsibility of the caller to provide your class valid pointers. There are constructs that the user should be using to guarantee that what is being passed to you is valid, such as smart pointers and other such classes. You can't be responsible for every single mistake that comes from the user using your class incorrectly.
Regards,
Paul McKenzie
From amcelroy:
Actually, that is quite easy to do in a non-erroneous way, as long as you are careful not to access any member data or the v-table of the possibly NULL class. (MFC code did it fairly often for reasons I no longer remember.)Quote:
If I pass a NULL pointer, call a Getter function to return a value of something from a NULL pointer, I don't understand how that can't possibly be an error.
Here's an example:
This happily outputs 300 before crashing. The "this" pointer is just a hidden parameter in each (non-static) member function. Since non-virtual functions aren't in the v-table the compiler is able to determine exactly which code to invoke during compilation. As long as no virtual functions are called and no class member data is used, the NULL this pointer won't be dereferenced and the non-virtual member function can successfully execute.Code:struct Test
{
int FunctionA(int x)
{
if (this == NULL)
{
return x * 100;
}
else
{
return x * m_i;
}
}
virtual int FunctionB(int x)
{
return x * 150;
}
int m_i;
};
int _tmain(int argc, _TCHAR* argv[])
{
Test * ptest = 0;
int y = ptest->FunctionA(3); // not in v-table so no crash
cout << y << endl;
int z = ptest->FunctionB(5); // crash here because it will attempt to dereference a v-table at NULL.
cout << z << endl;
return 0;
}
This is all pretty interesting, the finer points of C++ compilers. I'm just trying to be as responsible as possible in catching errors. I've tried to contain the damage the user can do, but there will invariably be something that someone does that will crash the program.
NULL was just an example, what about some a pointer to a random variable, do these cases still not cause crashes?
From amcelroy:
Well, it largely boils down to what Paul McKenzie was saying in posts #18 and #19. It's the whole "undefined behavior" idea. If the random variable points outside the program's address space you'll crash. If not, it could produce obvious, subtle, or unrecognizable errors. It might cause a side effect resulting in a seemingly inexplicable crash minutes or hours later (e.g. perhaps by overwriting a pointer stored somewhere else).Quote:
NULL was just an example, what about some a pointer to a random variable, do these cases still not cause crashes?
You're possibly too concerned with being robust. You certainly want your function to be robust, but if users of your function have a bug in their code, that's their problem, not yours. ;) Also, what if someone wants to use your function in speed-critical code? Extra checks for bad pointers (besides not being guaranteed to work for reasons others have described) would only slow the program down and would be useless once that someone has debugged his or her code.
Note that NULL very often isn't a bad pointer but is rather a sentinel value (perhaps indicating something hasn't been previously allocated). Many consider it good programming practice to set pointers to NULL when done with them so that if they get dereferenced unexpectedly a crash will be guaranteed rather than "undefined behavior".
If you do not know what code will be calling yours, then it is good idea to check whether a passed-in pointer is NULL or not. If it is not NULL, then assume it is valid.
If you are concerned about the validity of the data being passed to your function, the solution is to have your users get handles issued by you, and not just created willy-nilly by the user.
I mentioned this earlier -- you want the user to pass valid pointers to you, then you should be the one issuing the pointers to the user up front by making available a "Create" fiunction. The user want to destroy the pointer, then they must call your "Destroy" function. In this sense, you are basically creating handles for the user, and they must use this handle to do anything with your code.
With the above approach, you have total control of what gets created, what gets destroyed, and can legitimately check if a handle is valid or not. Your "poor-mans" approach is IMO a waste of time -- you need to create a proper factory/handle model to accomplish any real error checking.
For example, how is it that Windows never crashes if someone calls a WinAPI function with an invalid HWND? Internally the Windows system has a list of all the valid HWND's, so that when an API function is called, it looks up in the list for that passed-in value and determines whether to go forward with the function, or return an error.
Regards,
Paul McKenzie
When a function accepts as a parameter a memory pointer, there are 1 of 4 possibilites:
1) the pointer is correct and points to what is expected
2) the pointer is NULL. This may or may not be an error depending upon the interface specification
3) the pointer references valid memory in the program address space but does not point to what is expected
4) the pointer references invalid memory outside of the program address space
If you want to undertake pointer parameter checking, then 2) can be done easily, if required, by testing the pointer for NULL and if it is then throwing an exception. 4) will cause an exception when the memory is accessed - so use some statements that access the memory which won't be optimised away by the complier if the result isn't used. 3) can really only be checked by using the factory method as Paul outlined in post #29. This would require changes to all programs that use the function as they would have to obtain the factory produced handle and pass as function argument the factory handle rather than just a pointer to some memory. The only way that 3) can be checked for easily - and is not guarenteed - is to have some 'magic number' stored in a class member variable by the class constructor which can be tested whenever a pointer to the class is referenced.
What level of checking a particular function does on its provided arguments is really down to overall system design/architecture and the tradeoff between robustness and speed. In some environments the level of checking performed is determined by compile time pre-processor identifiers. So there is the 'debug' version with all checking on and the 'release' version with only the most basic (or no) checks. But whatever checking is done or not done on function parameters should be stated clearly in the function contract documentation so that users of the function are aware.