From b88776ba5a1d58d87b1a70ed73337c2e04e068f8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 28 Sep 2011 15:42:55 +0000 Subject: [PATCH] fix for crash with demo mode addon, modal operator loading a blend file would free all window data which was then accessed, causing a crash. --- source/blender/python/intern/bpy_rna.c | 12 +++- .../windowmanager/intern/wm_event_system.c | 70 ++++++++++--------- 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index cbd6affb117..271e4c72a25 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -6238,7 +6238,11 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param ParameterIterator iter; PointerRNA funcptr; int err= 0, i, flag, ret_len=0; - int is_static= RNA_function_flag(func) & FUNC_NO_SELF; + const char is_static= (RNA_function_flag(func) & FUNC_NO_SELF) != 0; + + /* annoying!, need to check if the screen gets set to NULL which is a + * hint that the file was actually re-loaded. */ + const char is_valid_screen= (CTX_wm_screen(C) != NULL); PropertyRNA *pret_single= NULL; void *retdata_single= NULL; @@ -6498,7 +6502,11 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param if(err != 0) { ReportList *reports; /* alert the user, else they wont know unless they see the console. */ - if (!is_static && ptr->data && RNA_struct_is_a(ptr->type, &RNA_Operator)) { + if ( (!is_static) && + (ptr->data) && + (RNA_struct_is_a(ptr->type, &RNA_Operator)) && + is_valid_screen == (CTX_wm_screen(C) != NULL)) + { wmOperator *op= ptr->data; reports= op->reports; } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index cfeaee18416..596fa35d597 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1223,41 +1223,47 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand retval= ot->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); - if(ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) - wm->op_undo_depth--; + /* when this is _not_ the case the modal modifier may have loaded + * a new blend file (demo mode does this), so we have to assume + * the event, operator etc have all been freed. - campbell */ + if(CTX_wm_manager(C) == wm) { - /* putting back screen context, reval can pass trough after modal failures! */ - if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) { - CTX_wm_area_set(C, area); - CTX_wm_region_set(C, region); - } - else { - /* this special cases is for areas and regions that get removed */ - CTX_wm_area_set(C, NULL); - CTX_wm_region_set(C, NULL); - } + if(ot->flag & OPTYPE_UNDO) + wm->op_undo_depth--; - if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) - wm_operator_reports(C, op, retval, 0); - - if(retval & OPERATOR_FINISHED) { - wm_operator_finished(C, op, 0); - handler->op= NULL; - } - else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { - WM_operator_free(op); - handler->op= NULL; - } - - /* remove modal handler, operator itself should have been cancelled and freed */ - if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { - WM_cursor_ungrab(CTX_wm_window(C)); + /* putting back screen context, reval can pass trough after modal failures! */ + if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) { + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); + } + else { + /* this special cases is for areas and regions that get removed */ + CTX_wm_area_set(C, NULL); + CTX_wm_region_set(C, NULL); + } - BLI_remlink(handlers, handler); - wm_event_free_handler(handler); - - /* prevent silly errors from operator users */ - //retval &= ~OPERATOR_PASS_THROUGH; + if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) + wm_operator_reports(C, op, retval, 0); + + if(retval & OPERATOR_FINISHED) { + wm_operator_finished(C, op, 0); + handler->op= NULL; + } + else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { + WM_operator_free(op); + handler->op= NULL; + } + + /* remove modal handler, operator itself should have been cancelled and freed */ + if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { + WM_cursor_ungrab(CTX_wm_window(C)); + + BLI_remlink(handlers, handler); + wm_event_free_handler(handler); + + /* prevent silly errors from operator users */ + //retval &= ~OPERATOR_PASS_THROUGH; + } } }