Skip to main content
GameDev.net gamedev.net
🔒 Locked

Exception from destructor?

Started by The C modest god Oct 28, 2005 at 2:50 PM 34 replies 4.7k views
Original Post
The C modest god
The C modest god
I have found a bug in the following code:

void 
InputDevice::GetPropertyDWORD (REFGUID PropType, DWORD & Data)
{
	DIPROPDWORD DIDWord;
	DIPROPHEADER DIProp;

	DIProp.dwHeaderSize = sizeof(DIPROPHEADER);
	DIProp.dwSize = sizeof (DIPROPDWORD);
	DIProp.dwHow = DIPH_DEVICE;
	DIProp.dwObj = 0;
	DIDWord.diph = DIProp;
	DIDWord.dwData = 0;

	// TODO: Watch out not to do &DIProp but &DIDWord.diph
	this->GetProperty (PropType, &DIProp); //<= &DIProp instead of &DIDWprd.diph cause a bug
	Data = DIDWord.dwData;
} // <= break place from exception
I have found this bug, but what bugged me is that an exception was throwing and my catch(...) didnt catch it. I guess that this is because the exception was throwen from within a destructor. In that case, how can such exception be caught and handled? Thanks in advance.
It's all about the wheel.Never blindly trust technoligy.I love my internal organs.Real men don't shower. Quote: Original post by Toolmaker Quote:
Rattrap
Rattrap
I know this isn't much of an answer, but I know it is very much discouraged to ever have exception throwing destructors because of this reason.
"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]
Kippesoep
Kippesoep
You can throw an exception from a destructor, but it's a very bad idea. The reason it's a bad idea is that you might actually be throwing an exception when your object is being destroyed as the result of another exception being handled.

Full info here.
Kippesoep
markr
markr
If you dereference a pointer with an incorrect type, it won't raise an exception. Instead, it's likely to cause a crash or data corruption, which could make anything happen.

So although throwing exceptions in destructors is something you shouldn't do, dereferencing pointers incorrectly, is something that you should to *even less*.

Throwing an exception in a destructor during stack unwinding from a previous exception will cause terminate() to be called (I think). This is bad, but at least it's a predictable kind of badness.

Handling pointers incorrectly could cause anything to happen, including corruption of data which later causes an error somewhere else entirely unrelated.

Mark
MaulingMonkey
MaulingMonkey
Quote:
Original post by The C modest god
I think there is a missunderstanding here.
I didnt say that I intentionally wrote code that throws an exception from a Dstr.
I just said that it seems like windows have thrown an exception from some dtr of his class, because my try/catch didnt catch this exception.
Why else would an exception wont be caught and the break will be at } of the method?


Sounds like you're talking about something like a windows access violation - in other words not a C++ exception - in other words not caught by C++'s exception handling mechanism.

You need to clarify: What kind of exception is occuring? Preferibly, copy and paste the exact message you recieve that lets you know that an exception is in fact occuring.
SirLuthor
SirLuthor
There's a very simple answer to this. Quit worrying about the exception and fix your code where it's sacking the stack! You've got much larger problems then exceptions not being caught right now if you're getting stack corruption. Get your priorities straight man!

Oh, and, if I recall correctly, you can hardly catch exceptions with the termination handler and resume execution. There's a reason why it's called the termination handler. It's named that way because your program is irrevocably screwed up, and Windows is bailing on it. You can supply your own termination handler, but there is, again if I recall correctly, no way to go from there to wherever you were before as if it were an extra catch.
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
ProgramMax
ProgramMax
You silly. You even describe in your code with comments what the problem is.

Don't say it is a bug in DirectX. You are passing the wrong thing to DirectX and expecting it to work. Obviously it shouldn't. That's not DirectX's fault.

Also this sort of run-time check that VC7.1 provides really isn't meant to be in your production code. So having something for the user to submit a bug when this exception rises isn't wise.

Rather this is for you to debug before you release. Other, normal bugs are the ones you want help finding. Not bugs that you cause.
ProgramMax
ProgramMax
Perhaps I should better describe the situation. Suppose you do this:

int * pMyInt;

pMyInt = NULL;

( * pMyInt ) = 7;

Obviously this will crash. It is trying to assign an invalid pointer.

So your origional question asked "How can you catch this un-catchable exception?" The answer is: You don't. Your code shouldn't ever assume that you will be assigning an invalid pointer. That's why they make these exceptions so difficult to catch.

Rather it is for the programmer to see while testing. They will go "Oh. Somewhere I'm doing X wrong. I need to go fix it."

Now I understand that we are human and make mistakes. And so perhaps a problem like this will slip into a release build. And if it does and it effects a user, it would be nice for the user to be able to submit the bug.

Perhaps a good suggestion is: If this program is crashing and cannot recover, perhaps a seperate program that is running will notice the crash and be able to gather the information. You could do this with shared memory and a watchdog timer(I think that's what they are called). So if your program doesn't reset the timer in shared memory, the second program assumes it crashed. So maybe have a timer that must be reset every 3 seconds or so?

I don't know...I have never written something like what you are doing. I hope the tips I provided are helpful.
SirLuthor
SirLuthor
Quote:
Original post by The C modest god
The bug was very simple, if you didnt read the code I wrote, it was due to the bad design of DirectX. It was the method of directX which corrupted the memory.
You are very optimistic if you think you can resume your program after an exception and nothing bad will happen.
All I want to do is to catch the exception, report on it for the user and save some information/send mail and then end my program's life.

Aha. Clearly because it crashes with some code you wrote, the blame must lie with DirectX. I guess that's why thousands of other people can use it constantly without crashing? Your excuse makes no sense, because DirectX is rarely, if ever, to blame. If it was, then it wouldn't be in such widespread use, and your bug would have been noticed and reported, and most likely fixed by now. Corrupted stack, access violations, etc, they are NEVER supposed to happen. There is no point in adding in things to handle them, because as long as you are doing your job/hobby properly, they should never occur. If you have access violations or stack corruption knowingly in something you are releasing to users, you should be slapped, and then made to fix your broken code. Because that's what it is. BROKEN.

If you need to catch that sort of thing while debugging, then use a debugger. That's what it's for. It's not there so you can go and hack in your own debugging and re-invent the hugely complex wheel.

It is a poor craftsman that blames his tools.
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
arm
arm
Quote:
My program catchs the exception caused by the example you gave, since it is not in a dtr.
Imagine you write a class in C++, it would be good if that class wont allow you to do any memory corruption that may be discovered only later on in the program.
Like a class of an array which wont let you to access memory which is out of the alloceted memory for the array. This class "protects" you from writting into memory which you should not write into.
It would be nice if DirectX interfaces would be like that as well.
I hope that in DX10 they will write better DirectX interface.


If I understand you correctly, you're referring to a bound's-checked array (like Java has). The trouble with these is performance. Every read to and write from the array must be checked, which obviously uses up a lot of time when you do a lot of reads and writes. As others have said, if your program is written and debugged carefully, these bounds errors should not happen.

Quote:
Is it so hard to accept that DirectX method corrupts memory?
Of course it does, because it does something entirely bad in terms of C++ or programming in general.
It gets a pointer of a structure and assumes it is a variable of a larger structure and based on that and the address of the internal structure it calculates the address of variable of the parent structure and deals with them.
That's really a bad thing.
Please reply for this only if you have already used the method I am talking about.


Ditto. If you have to validate a class/struct/etc everytime you access one of its members you will incurr a penalty.

Programming, especially performance intensive programming (i.e. games) is all about compromise -- until we get those ultra-fast Quantum Computers there will always be tradeoffs to be made.

arm.
Nitage
Nitage
In related news, I found a bug with the MS std::vector:
std::vector<int> i;i[252721] = 50;//Oh noes! std vectors has a bug which corrupts memory!!!1!

ProgramMax
ProgramMax
You are still being silly. I don't mean to be pushy but I think you aren't quite grasping what we mean.

First, DirectX isn't C++-only. So it cannot do any C++-only things. You suggest that it magically should anyway.

Second, you are calling a DirectX function that asks for a variable of type A. You are passing a variable of type B. Then you say "Well DirectX should have known not to go outside the bounds of a type B." But your claim is not well founded. DirectX did EVERYTHING in its power to do exactly that. That's why the variable being passed has a specific type. But you are providing something else. There is NO POSSIBLE WAY short of RTTI for DirectX to check the size of a type at run-time. So the problem isn't DirectX not checking bounds or corrupting memory. The problem is you are passing the wrong thing.

I really want to stress that. Quit blaming DirectX. DirectX isn't doing anything wrong.

And finally, the example I gave above wasn't wether or not the exception could be caught. It was to show that I am clearly doing something I shouldn't. It's a problem that should never be in release code. In that reguard it is similar to the problem you describe. I was trying to show the similarities and make it more obvious what you should do.
rip-off
rip-off
Quote:
Original post by The C modest god
Quote:
Original post by Nitage
In related news, I found a bug with the MS std::vector:
*** Source Snippet Removed ***

It is a bug if it does this and wont throw an exception, but I think it does throw an exception in that case.
I am sure your will be wasting very little time on fixing bugs and that you are defenitly capable of fixing a bug that occurs only on the end user computer and not on your own computer.


the whole point of operator[] in vector is to allow unchecked access for speed.

in order to throw an exception, it would have to perform range checking.

this method only works *if you give it a valid index*. if you don't , its your fault, and that is clearly documented. it's YOUR bug if you fail to comly with a methods preconditions.
Quote:

Is it so hard to accept that DirectX method corrupts memory?
Of course it does, because it does something entirely bad in terms of C++ or programming in general.
It gets a pointer of a structure and assumes it is a variable of a larger structure and based on that and the address of the internal structure it calculates the address of variable of the parent structure and deals with them.
That's really a bad thing.
Please reply for this only if you have already used the method I am talking about.
Quote:
Original post by The C modest god
It is very simple actually to test that the method has bad behaviour.
If you give it paramters which you you are not suppos to pass to it.
Such as address of a different structure or address of the right structure but which is not a field of a parent structure as the documentation says it should be. If you do this and the method doesnt give you compile or runtime error then the method is not desgined well.


why would you *intentionally* pass a parameter you know is incorrect?

does it have the same problems if you were to, i don't know, pass it a parameter of a type it _is_ expecting? if so, you've found a bug. otherwise you are basically doing something it was never designed to do and complaining...
ProgramMax
ProgramMax
Oops maybe I should clerify a tad more. I said there is no way for DirectX to do what you want without RTTI. But RTTI is another C++-only thing. .NET languages have reflection, which is similar. But my point is not all languages have this. And so DirectX cannot use it.

Also just so you know. The exception ISN'T BEING THROWN IN A DTOR. At each block closure VC7.1 has injected code to check if the stack was corrupted inside that block (because you have that option enabled).

So uh...just more reason for you to stop blaming DirectX. DirectX isn't throwing in a dtor.
ProgramMax
ProgramMax
You don't. It is being caught and handled so it could display to you that there was that error.

This is why I mentioned that this is for the coder, not the user, to see. That way the coder (you) can go "Oh. I have a problem with X. I need to fix it."

You should not write your code to assume this error will happen. You should assume it won't happen infact.

Perhaps my previous posts will make more sense now.
ProgramMax
ProgramMax
I'm doing a terrible job explaining the details tonight. Anyway...this should also help clear up the problem.

Have you heard about buffer overrun hacks? The idea is a program will have a buffer of maybe 100 bytes. Some hacker will send 1000 bytes instead. The program will accidently fill the buffer...and overrun the buffer. Eventually the code will try to run code that has now been overwritten by that 1000-byte buffer.

So the hacker can inject their code into your program. VERY bad problem. And a TON of programs have this problem.


"So how does this relate to me?" you ask. Well that's a good question. After this exploit was discovered there was much demand to get some quick solution out that prevents this. Having every company tediously go through all their code and look won't work. And even then, there will be mistakes.

So Microsoft saved the day by adding run-time security checks in their compilers. The idea is not to prevent the problem from happening...that takes fixing the code. The idea is to detect if the problem occured. If so, shut the program down so bad hacker-code never gets a chance to run.


"So you are saying that this run-time security check exception I am getting isn't supposed to be caught?" you ponder. Exactly! An exception handler is just more code to be run. And you have no garuntee that it isn't hacker code. So running an exception handler would be bad.


"Ah. Now I see why I should not catch this error." Correct. You also see why you should assume it never happens. Also that might explain how it is a quick-fix and really shouldn't be in production code.


"But I don't have a hacker injecting code into my project!" That is also correct. But your code has no way of knowing that. It just sets up certain security measures. You have written your code to break those measures. Thus it is reacting like it should.
Lawgiver
Lawgiver
I think C Modest God is saying that the DirectX function should have taken as a second parameter a pointer to an INT/DWORD/LONG (whatever the actual parameter should be) instead of a void *. Then, his bad behavior would have been catched at compile time.

Robin
ProgramMax
ProgramMax
It does. It takes a type LPDIPROPHEADER.

http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/input/ref/functs/functions.asp
SirLuthor
SirLuthor
Quote:
Original post by The C modest god
Is it so hard to accept that DirectX method corrupts memory?
Of course it does, because it does something entirely bad in terms of C++ or programming in general.
It gets a pointer of a structure and assumes it is a variable of a larger structure and based on that and the address of the internal structure it calculates the address of variable of the parent structure and deals with them.
That's really a bad thing.
Please reply for this only if you have already used the method I am talking about.

It is very simple actually to test that the method has bad behaviour.
If you give it paramters which you you are not suppos to pass to it.
Such as address of a different structure or address of the right structure but which is not a field of a parent structure as the documentation says it should be. If you do this and the method doesnt give you compile or runtime error then the method is not desgined well.

DirectX is not meant to be bulletproof code. Even when passed the right parameters, function calls can still fail, due to things entirely out of your reach, such as a hardware problem, etc. DirectX is not about making a perfectly safe set of code. It's about making things go as fast as possible. If you insist on being dim and passing it the wrong parameters, even when you know they are wrong, what do you expect, a pie in the mail? You deserve everything that happens to you. The SDK clearly defines what should and shouldn't be done; if you aren't good enough to be able to read and comprehend that, perhaps you shouldn't be playing around with things outside of your grasp. Plenty of things corrupt memory. But if you go and make the DirectX calls check everything, every time, for programmers being dense and backwards, even after they have been told exactly what to do, then things will slow down, and that is exactly the opposite of what needs to happen.

DirectX is advanced, either follow the instructions, or keep on playing with your perfectly safe methods.
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
ProgramMax
ProgramMax
It is not casting it to a char * or doing any type-unsafe thing that you mention. At the bottom I have included a link to how a DIPROPHEADER type is defined. Notice that your function asks for a LPDIPROPHEADER, not a DIPROPHEADER. But an LP* is defined to a pointer to * in the DirectX headers. So you are supposed to be passing in a pointer to a DIPROPHEADER (or a LPDIPROPHEADER).

No pointer voodoo is happening behind the scenes.

Also if it was accessing data outside the struct then you would probably get access violation errors. That's not what's happening.

http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/input/ref/functs/functions.asp

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.