fix [#29537] file/save crashes when target path isnt found
authorCampbell Barton <ideasman42@gmail.com>
Mon, 12 Dec 2011 18:06:36 +0000 (18:06 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 12 Dec 2011 18:06:36 +0000 (18:06 +0000)
bug was that uiPupMenuSaveOver(...) could run the WM API call function which freed the operator, within the low level invoke function which kept using the freed memory.

Changed uiPupMenuSaveOver(...) to only show a popup so the caller needs to check if the file exists and should be immediately written (which was done everywhere except for blend saving anyway).

* added note that operators invoke/exec funcs cant call WM_operator_call(...) on themselves, ends up using freed memory.
* added BLI_is_file(path), checks the file exists and isnt a directory.

source/blender/blenlib/BLI_fileops.h
source/blender/blenlib/intern/storage.c
source/blender/editors/interface/interface_regions.c
source/blender/editors/space_file/file_ops.c
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_operators.c

index 712429716a619a3f626fffd2da9b1a3f411e2e37..2e8f1a5512eaaffb2a7bcbc69ddce8fd20646cc3 100644 (file)
@@ -56,6 +56,7 @@ int    BLI_create_symlink(const char *path, const char *to);
 struct direntry;
 
 int    BLI_is_dir(const char *path);
+int    BLI_is_file(const char *path);
 void   BLI_dir_create_recursive(const char *dir);
 double BLI_dir_free_space(const char *dir);
 char  *BLI_current_working_dir(char *dir, const int maxlen);
index 1ef254d355f4bf7e7c344d19bbd604451109d65a..001b191155d571d016e4d43c9ad34cfc529adeff 100644 (file)
@@ -471,6 +471,12 @@ int BLI_is_dir(const char *file)
        return S_ISDIR(BLI_exists(file));
 }
 
+int BLI_is_file(const char *path)
+{
+       int mode= BLI_exists(path);
+       return (mode && !S_ISDIR(mode));
+}
+
 LinkNode *BLI_file_read_as_lines(const char *name)
 {
        FILE *fp= fopen(name, "r");
index 58c3c0130b8d4bc96f4e5ca9b8695e8a531520ea..b89a80bb0d759d466d978e85ab6b2e933f4b9691 100644 (file)
@@ -2481,22 +2481,14 @@ void uiPupMenuOkee(bContext *C, const char *opname, const char *str, ...)
        va_end(ap);
 }
 
+/* note, only call this is the file exists,
+ * the case where the file does not exist so can be saved without a
+ * popup must be checked for already, since saving from here
+ * will free the operator which will break invoke().
+ * The operator state for this is implicitly OPERATOR_RUNNING_MODAL */
 void uiPupMenuSaveOver(bContext *C, wmOperator *op, const char *filename)
 {
-       size_t len= strlen(filename);
-
-       if(len==0)
-               return;
-
-       if(filename[len-1]=='/' || filename[len-1]=='\\') {
-               uiPupMenuError(C, "Cannot overwrite a directory");
-               WM_operator_free(op);
-               return;
-       }
-       if(BLI_exists(filename)==0)
-               operator_cb(C, op, 1);
-       else
-               confirm_operator(C, op, "Save Over", filename);
+       confirm_operator(C, op, "Save Over", filename);
 }
 
 void uiPupMenuNotice(bContext *C, const char *str, ...)
index 69c192b077bc604889c3bb4940ec4d415ddbffe0..daa2031bb5f72e6196d79840cb9be35b93f7c5e7 100644 (file)
@@ -715,7 +715,7 @@ int file_draw_check_exists(SpaceFile *sfile)
                        if(RNA_boolean_get(sfile->op->ptr, "check_existing")) {
                                char filepath[FILE_MAX];
                                BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
-                               if(BLI_exists(filepath) && !BLI_is_dir(filepath)) {
+                               if(BLI_is_file(filepath)) {
                                        return TRUE;
                                }
                        }
@@ -1143,8 +1143,8 @@ int file_directory_exec(bContext *C, wmOperator *UNUSED(unused))
                        BLI_dir_create_recursive(sfile->params->dir);
                }
 
-               /* special case, user may have pasted a fulepath into the directory */
-               if(BLI_exists(sfile->params->dir) && BLI_is_dir(sfile->params->dir) == 0) {
+               /* special case, user may have pasted a filepath into the directory */
+               if(BLI_is_file(sfile->params->dir)) {
                        char path[sizeof(sfile->params->dir)];
                        BLI_strncpy(path, sfile->params->dir, sizeof(path));
                        BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
index 9d8f68115cf5b8a25a38c5714eeb417e9c9cf498..38f268979983a457de6bc1fdbe8e9e8612784d83 100644 (file)
@@ -597,7 +597,9 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
        
 }
 
-/* for running operators with frozen context (modal handlers, menus) */
+/* for running operators with frozen context (modal handlers, menus)
+ *
+ * warning: do not use this within an operator to call its self! [#29537] */
 int WM_operator_call(bContext *C, wmOperator *op)
 {
        return wm_operator_exec(C, op, 0);
index 31d276fee015dbc53601e70897899cd41bdfdf58..fb375f1d61f88ca6bac8d37cc4b53d79109949f5 100644 (file)
@@ -2003,6 +2003,7 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(
 {
        char name[FILE_MAX];
        int check_existing=1;
+       int ret;
        
        /* cancel if no active window */
        if (CTX_wm_window(C) == NULL)
@@ -2027,16 +2028,20 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(
                        check_existing = 0;
        
        if (G.save_over) {
-               if (check_existing)
+               if (check_existing && BLI_exists(name)) {
                        uiPupMenuSaveOver(C, op, name);
+                       ret= OPERATOR_RUNNING_MODAL;
+               }
                else {
-                       wm_save_as_mainfile_exec(C, op);
+                       ret= wm_save_as_mainfile_exec(C, op);
                }
-       } else {
+       }
+       else {
                WM_event_add_fileselect(C, op);
+               ret= OPERATOR_RUNNING_MODAL;
        }
        
-       return OPERATOR_RUNNING_MODAL;
+       return ret;
 }
 
 static void WM_OT_save_mainfile(wmOperatorType *ot)