msvcrt: Destroy exception object when frame storing it is unwound.

Thrown object was incorrectly freed in following situation:
try {
     throw obj;
} catch(object &obj) {
     try {
         throw 1;
     } catch(...) {}

     //use object here
}

Signed-off-by: Piotr Caban <piotr@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Piotr Caban 2016-03-15 13:41:20 +01:00 committed by Alexandre Julliard
parent 2d4b48a58d
commit f085be3028
1 changed files with 10 additions and 17 deletions

View File

@ -131,6 +131,7 @@ DWORD CDECL cxx_frame_handler( PEXCEPTION_RECORD rec, cxx_exception_frame* frame
PCONTEXT context, EXCEPTION_REGISTRATION_RECORD** dispatch, PCONTEXT context, EXCEPTION_REGISTRATION_RECORD** dispatch,
const cxx_function_descr *descr, const cxx_function_descr *descr,
EXCEPTION_REGISTRATION_RECORD* nested_frame, int nested_trylevel ); EXCEPTION_REGISTRATION_RECORD* nested_frame, int nested_trylevel );
BOOL __cdecl _IsExceptionObjectToBeDestroyed(const void*);
/* call a function with a given ebp */ /* call a function with a given ebp */
static inline void *call_ebp_func( void *func, void *ebp ) static inline void *call_ebp_func( void *func, void *ebp )
@ -361,9 +362,18 @@ static DWORD catch_function_nested_handler( EXCEPTION_RECORD *rec, EXCEPTION_REG
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
{ {
struct catch_func_nested_frame *nested_frame = (struct catch_func_nested_frame *)frame; struct catch_func_nested_frame *nested_frame = (struct catch_func_nested_frame *)frame;
PEXCEPTION_RECORD prev_rec = nested_frame->rec;
if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
{ {
if (prev_rec->ExceptionCode == CXX_EXCEPTION)
{
void *object = (void*)prev_rec->ExceptionInformation[1];
cxx_exception_type *info = (cxx_exception_type*) prev_rec->ExceptionInformation[2];
if (info && info->destructor && _IsExceptionObjectToBeDestroyed(object))
call_dtor( info->destructor, object);
}
msvcrt_get_thread_data()->exc_record = nested_frame->prev_rec; msvcrt_get_thread_data()->exc_record = nested_frame->prev_rec;
return ExceptionContinueSearch; return ExceptionContinueSearch;
} }
@ -372,7 +382,6 @@ static DWORD catch_function_nested_handler( EXCEPTION_RECORD *rec, EXCEPTION_REG
if(rec->ExceptionCode == CXX_EXCEPTION) if(rec->ExceptionCode == CXX_EXCEPTION)
{ {
PEXCEPTION_RECORD prev_rec = nested_frame->rec;
if((rec->ExceptionInformation[1] == 0 && rec->ExceptionInformation[2] == 0) || if((rec->ExceptionInformation[1] == 0 && rec->ExceptionInformation[2] == 0) ||
(prev_rec->ExceptionCode == CXX_EXCEPTION && (prev_rec->ExceptionCode == CXX_EXCEPTION &&
rec->ExceptionInformation[1] == prev_rec->ExceptionInformation[1] && rec->ExceptionInformation[1] == prev_rec->ExceptionInformation[1] &&
@ -388,22 +397,6 @@ static DWORD catch_function_nested_handler( EXCEPTION_RECORD *rec, EXCEPTION_REG
rec->ExceptionInformation[1], rec->ExceptionInformation[2]); rec->ExceptionInformation[1], rec->ExceptionInformation[2]);
} }
} }
else if (nested_frame->prev_rec && nested_frame->prev_rec->ExceptionCode == CXX_EXCEPTION &&
nested_frame->prev_rec->ExceptionInformation[1] == prev_rec->ExceptionInformation[1] &&
nested_frame->prev_rec->ExceptionInformation[2] == prev_rec->ExceptionInformation[2])
{
TRACE("detect threw new exception in catch block - not owning old(obj: %lx type: %lx)\n",
prev_rec->ExceptionInformation[1], prev_rec->ExceptionInformation[2]);
}
else if (prev_rec->ExceptionCode == CXX_EXCEPTION) {
/* new exception in exception handler, destroy old */
void *object = (void*)prev_rec->ExceptionInformation[1];
cxx_exception_type *info = (cxx_exception_type*) prev_rec->ExceptionInformation[2];
TRACE("detect threw new exception in catch block - destroy old(obj: %p type: %p)\n",
object, info);
if(info && info->destructor)
call_dtor( info->destructor, object );
}
else else
{ {
TRACE("detect threw new exception in catch block\n"); TRACE("detect threw new exception in catch block\n");