- registering new python classes runs the free functions on existing classes.
authorCampbell Barton <ideasman42@gmail.com>
Fri, 14 Aug 2009 12:29:55 +0000 (12:29 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 14 Aug 2009 12:29:55 +0000 (12:29 +0000)
- print an error if RNA Structs are freed with a python pointer set to help with debugging leaks.
- fix for unlikely eternal loop in unit conversion.

source/blender/blenkernel/intern/unit.c
source/blender/makesrna/intern/rna_define.c
source/blender/makesrna/intern/rna_render.c
source/blender/makesrna/intern/rna_ui.c
source/blender/python/intern/bpy_interface.c
source/blender/python/intern/bpy_rna.c
source/blender/python/intern/bpy_rna.h
source/blender/windowmanager/intern/wm_init_exit.c

index ba609fc5611a78eb29374e199e6a965e0007c857..140f155abc39d9bbb574d262523481813e42097d 100644 (file)
@@ -294,9 +294,9 @@ static char *unit_find_str(char *str, char *substr)
 
 static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pref, bUnitDef *unit, char *replace_str)
 {
-       char *str_found= unit_find_str(str, replace_str);
+       char *str_found;
 
-       if(str_found) { /* XXX - investigate, does not respect len_max properly  */
+       if((len_max>0) && (str_found= unit_find_str(str, replace_str))) { /* XXX - investigate, does not respect len_max properly  */
                int len, len_num, len_name, len_move, found_ofs;
 
                found_ofs = (int)(str_found-str);
@@ -330,20 +330,22 @@ static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pr
                        memcpy(str_found, str_tmp, len_num); /* without the string terminator */
                }
 
-               str[len_max-1]= '\0'; /* since the null terminator wont be moved */
-               return 1;
+               /* since the null terminator wont be moved if the stringlen_max
+                * was not long enough to fit everything in it */
+               str[len_max-1]= '\0';
+               return found_ofs + len_num;
        }
        return 0;
 }
 
 static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref, bUnitDef *unit)
 {      
-       int change= 0;
-       change |= unit_scale_str(str, len_max, str_tmp, scale_pref, unit, unit->name_short);
-       change |= unit_scale_str(str, len_max, str_tmp, scale_pref, unit, unit->name_plural);
-       change |= unit_scale_str(str, len_max, str_tmp, scale_pref, unit, unit->name_alt);
-       change |= unit_scale_str(str, len_max, str_tmp, scale_pref, unit, unit->name);
-       return change;
+       int ofs= 0;
+       ofs += unit_scale_str(str+ofs, len_max-ofs, str_tmp, scale_pref, unit, unit->name_short);
+       ofs += unit_scale_str(str+ofs, len_max-ofs, str_tmp, scale_pref, unit, unit->name_plural);
+       ofs += unit_scale_str(str+ofs, len_max-ofs, str_tmp, scale_pref, unit, unit->name_alt);
+       ofs += unit_scale_str(str+ofs, len_max-ofs, str_tmp, scale_pref, unit, unit->name);
+       return ofs;
 }
 
 static int unit_find(char *str, bUnitDef *unit)
@@ -401,12 +403,12 @@ int bUnit_ReplaceString(char *str, int len_max, char *str_prev, double scale_pre
                                usys_iter= unit_get_system(system_iter, type);
                                for(unit= usys_iter->units; unit->name; unit++) {
 
-                                       if(unit->flag & B_UNIT_DEF_SUPPRESS)
-                                               continue;
-
-                                       /* incase there are multiple instances */
-                                       while(unit_replace(str, len_max, str_tmp, scale_pref, unit))
-                                               change= 1;
+                                       if((unit->flag & B_UNIT_DEF_SUPPRESS) == 0) {
+                                               int ofs = 0;
+                                               /* incase there are multiple instances */
+                                               while((ofs=unit_replace(str+ofs, len_max-ofs, str_tmp, scale_pref, unit)))
+                                                       change= 1;
+                                       }
                                }
                        }
                }
index 5f1a069d876b84e2ba32881b5c042c717d66d3d8..ffbacdee69fc6135cbc56375b52c721ba2451b9a 100644 (file)
@@ -465,6 +465,12 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
        PropertyRNA *prop, *nextprop;
        PropertyRNA *parm, *nextparm;
 
+       if(srna->flag & STRUCT_RUNTIME) {
+               if(RNA_struct_py_type_get(srna)) {
+                       fprintf(stderr, "StructRNA \"%s\" freed while holdng a python reference\n", srna->name);
+               }
+       }
+
        for(prop=srna->cont.properties.first; prop; prop=nextprop) {
                nextprop= prop->next;
 
@@ -496,6 +502,7 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
 
        if(srna->flag & STRUCT_RUNTIME)
                rna_freelinkN(&brna->structs, srna);
+
 #endif
 }
 
index 7268d560282a1c2ddeb65271da7a8411acfc157c..040284cb07b9702c055cbfc2256c0f44601f8b38 100644 (file)
@@ -106,6 +106,9 @@ static void rna_RenderEngine_unregister(const bContext *C, StructRNA *type)
        if(!et)
                return;
        
+       et->ext.free(et->ext.data);                     /* decref's the PyObject that the srna owns */
+       RNA_struct_py_type_set(type, NULL);     /* NULL the srna's value so RNA_struct_free wont complain of a leak */
+
        BLI_freelinkN(&R_engines, et);
        RNA_struct_free(&BLENDER_RNA, type);
 }
index 590f85fedd76b7c3b34032b085be9b25b5b68e9f..5a33bcd6374a96b3f9170e00a68661bcc6e0962a 100644 (file)
@@ -138,6 +138,9 @@ static void rna_Panel_unregister(const bContext *C, StructRNA *type)
        if(!(art=region_type_find(NULL, pt->space_type, pt->region_type)))
                return;
        
+       pt->ext.free(pt->ext.data);                     /* decref's the PyObject that the srna owns */
+       RNA_struct_py_type_set(type, NULL);     /* NULL the srna's value so RNA_struct_free wont complain of a leak */
+
        BLI_freelinkN(&art->paneltypes, pt);
        RNA_struct_free(&BLENDER_RNA, type);
 
@@ -233,6 +236,9 @@ static void rna_Header_unregister(const bContext *C, StructRNA *type)
        if(!(art=region_type_find(NULL, ht->space_type, RGN_TYPE_HEADER)))
                return;
        
+       ht->ext.free(ht->ext.data);                     /* decref's the PyObject that the srna owns */
+       RNA_struct_py_type_set(type, NULL);     /* NULL the srna's value so RNA_struct_free wont complain of a leak */
+
        BLI_freelinkN(&art->headertypes, ht);
        RNA_struct_free(&BLENDER_RNA, type);
 
@@ -347,6 +353,9 @@ static void rna_Menu_unregister(const bContext *C, StructRNA *type)
        if(!(art=region_type_find(NULL, mt->space_type, RGN_TYPE_HEADER)))
                return;
        
+       mt->ext.free(mt->ext.data);                     /* decref's the PyObject that the srna owns */
+       RNA_struct_py_type_set(type, NULL);     /* NULL the srna's value so RNA_struct_free wont complain of a leak */
+
        BLI_freelinkN(&art->menutypes, mt);
        RNA_struct_free(&BLENDER_RNA, type);
 
index eedbe3b224f1580a4d3994d54b9d733260502c8c..ca5f933de803084036a1d8abc3fdd5b435a11d18 100644 (file)
@@ -270,10 +270,14 @@ void BPY_start_python( int argc, char **argv )
 
 void BPY_end_python( void )
 {
+       fprintf(stderr, "Ending Python!\n");
+
        PyGILState_Ensure(); /* finalizing, no need to grab the state */
        
        // free other python data.
-       //BPY_rna_free_types();
+       pyrna_free_types();
+
+       /* clear all python data from structs */
        
        Py_Finalize(  );
        
@@ -292,6 +296,8 @@ void BPY_end_python( void )
 
        printf("\n");
 
+       fprintf(stderr, "Ending Python Done!\n");
+
 #endif
 
 }
index 0c03b439e78fc9d0b5f03dde4687749961dab5bd..c71d7c7d90dc94c48fd459357cd8388b8c13cec9 100644 (file)
@@ -2319,17 +2319,22 @@ PyObject* pyrna_srna_Subtype(StructRNA *srna)
                if(base && base != srna) {
                        /*/printf("debug subtype %s %p\n", RNA_struct_identifier(srna), srna); */
                        py_base= pyrna_srna_Subtype(base);
+                       Py_DECREF(py_base); /* srna owns, this is only to pass as an arg */
                }
                
                if(py_base==NULL) {
                        py_base= (PyObject *)&pyrna_struct_Type;
-                       Py_INCREF(py_base);
                }
                
-               newclass = PyObject_CallFunction(       (PyObject*)&PyType_Type, "s(N){ssss}", idname, py_base, "__module__","bpy.types", "__doc__",descr);
+               /* always use O not N when calling, N causes refcount errors */
+               newclass = PyObject_CallFunction(       (PyObject*)&PyType_Type, "s(O){ssss}", idname, py_base, "__module__","bpy.types", "__doc__",descr);
 
                if (newclass) {
+
+                       /* incref's the new class (has 2 now)
+                        * srna owns one, and the other is owned by the caller */
                        pyrna_subtype_set_rna(newclass, srna);
+
                        // PyObSpit("NewStructRNA Type: ", (PyObject *)newclass);
 
                        /* attach functions into the class
@@ -2353,9 +2358,21 @@ PyObject* pyrna_srna_Subtype(StructRNA *srna)
        return newclass;
 }
 
+/* use for subtyping so we know which srna is used for a PointerRNA */
+static StructRNA *srna_from_ptr(PointerRNA *ptr)
+{
+       if(ptr->type == &RNA_Struct) {
+               return ptr->data;
+       }
+       else {
+               return ptr->type;
+       }
+}
+
+/* always returns a new ref, be sure to decref when done */
 PyObject* pyrna_struct_Subtype(PointerRNA *ptr)
 {
-       return pyrna_srna_Subtype((ptr->type == &RNA_Struct) ? ptr->data : ptr->type);
+       return pyrna_srna_Subtype(srna_from_ptr(ptr));
 }
 
 /*-----------------------CreatePyObject---------------------------------*/
@@ -2371,7 +2388,7 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr )
                
                if (tp) {
                        pyrna = (BPy_StructRNA *) tp->tp_alloc(tp, 0);
-                       Py_DECREF(tp);
+                       Py_DECREF(tp); /* srna owns, cant hold a ref */
                }
                else {
                        fprintf(stderr, "Could not make type\n");
@@ -2970,11 +2987,46 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par
 
 static void bpy_class_free(void *pyob_ptr)
 {
+       PyObject *self= (PyObject *)pyob_ptr;
+       PyGILState_STATE gilstate;
+
+       gilstate = PyGILState_Ensure();
+
+       PyDict_Clear(((PyTypeObject*)self)->tp_dict);
+
        if(G.f&G_DEBUG) {
-               if(((PyObject *)pyob_ptr)->ob_refcnt > 1)
-                       PyObSpit("zombie class - ref should be 1", (PyObject *)pyob_ptr);
+               if(self->ob_refcnt > 1) {
+                       PyObSpit("zombie class - ref should be 1", self);
+               }
        }
+
        Py_DECREF((PyObject *)pyob_ptr);
+
+       PyGILState_Release(gilstate);
+}
+
+void pyrna_free_types(void)
+{
+       PointerRNA ptr;
+       PropertyRNA *prop;
+
+       /* avoid doing this lookup for every getattr */
+       RNA_blender_rna_pointer_create(&ptr);
+       prop = RNA_struct_find_property(&ptr, "structs");
+
+
+       RNA_PROP_BEGIN(&ptr, itemptr, prop) {
+               StructRNA *srna= srna_from_ptr(&itemptr);
+               void *py_ptr= RNA_struct_py_type_get(srna);
+
+               if(py_ptr) {
+#if 0  // XXX - should be able to do this but makes python crash on exit
+                       bpy_class_free(py_ptr);
+#endif
+                       RNA_struct_py_type_set(srna, NULL);
+               }
+       }
+       RNA_PROP_END;
 }
 
 PyObject *pyrna_basetype_register(PyObject *self, PyObject *args)
index 9138fd511b06ac8ef974d57c9a605872fa0cace6..d14b7f1addb05b58cc03969152a5141e272da8d3 100644 (file)
@@ -83,4 +83,7 @@ PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw);
 PyObject *pyrna_basetype_register(PyObject *self, PyObject *args);
 PyObject *pyrna_basetype_unregister(PyObject *self, PyObject *args);
 
+/* called before stopping python */
+void pyrna_free_types(void);
+
 #endif
index 57e028670e71a5672bb0318797afa539ac1986e8..c679cbcab53e71303968739be892f6ebfb8e6531 100644 (file)
@@ -208,12 +208,6 @@ void WM_exit(bContext *C)
        
        BKE_freecubetable();
        
-       /* before free_blender so py's gc happens while library still exists */
-       /* needed at least for a rare sigsegv that can happen in pydrivers */
-#ifndef DISABLE_PYTHON
-       BPY_end_python();
-#endif
-       
        fastshade_free_render();        /* shaded view */
        ED_preview_free_dbase();        /* frees a Main dbase, before free_blender! */
        wm_free_reports(C);                     /* before free_blender! - since the ListBases get freed there */
@@ -233,6 +227,18 @@ void WM_exit(bContext *C)
        
 //     free_txt_data();
        
+
+#ifndef DISABLE_PYTHON
+       /* XXX - old note */
+       /* before free_blender so py's gc happens while library still exists */
+       /* needed at least for a rare sigsegv that can happen in pydrivers */
+
+       /* Update for blender 2.5, move after free_blender because blender now holds references to PyObject's
+        * so decref'ing them after python ends causes bad problems every time
+        * the pyDriver bug can be fixed if it happens again we can deal with it then */
+       BPY_end_python();
+#endif
+
        libtiff_exit();
        
 #ifdef WITH_QUICKTIME
@@ -256,7 +262,7 @@ void WM_exit(bContext *C)
        UI_exit();
        BKE_userdef_free();
 
-       RNA_exit();
+       RNA_exit(); /* should be after BPY_end_python so struct python slots are cleared */
        
        wm_ghost_exit();