Revision: 37575
          
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=37575
Author:   campbellbarton
Date:     2011-06-17 02:22:38 +0000 (Fri, 17 Jun 2011)
Log Message:
-----------
fix [#27681] Python: crash assigning a 'set' to an array

Modified Paths:
--------------
    trunk/blender/CMakeLists.txt
    trunk/blender/source/blender/python/intern/bpy_rna.c
    trunk/blender/source/blender/python/intern/bpy_rna_array.c

Modified: trunk/blender/CMakeLists.txt
===================================================================
--- trunk/blender/CMakeLists.txt        2011-06-17 00:39:59 UTC (rev 37574)
+++ trunk/blender/CMakeLists.txt        2011-06-17 02:22:38 UTC (rev 37575)
@@ -50,7 +50,7 @@
 cmake_minimum_required(VERSION 2.8)
 
 # this starts out unset
-set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/build_files/cmake/Modules/")
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/build_files/cmake/Modules")
 
 # quiet output for Makefiles, 'make -s' helps too
 # set_property(GLOBAL PROPERTY RULE_MESSAGES OFF)

Modified: trunk/blender/source/blender/python/intern/bpy_rna.c
===================================================================
--- trunk/blender/source/blender/python/intern/bpy_rna.c        2011-06-17 
00:39:59 UTC (rev 37574)
+++ trunk/blender/source/blender/python/intern/bpy_rna.c        2011-06-17 
02:22:38 UTC (rev 37575)
@@ -1380,12 +1380,8 @@
 
 
        if (RNA_property_array_check(ptr, prop)) {
-               int ok= 1;
-
                /* done getting the length */
-               ok= pyrna_py_to_array(ptr, prop, data, value, error_prefix);
-
-               if (!ok) {
+               if(pyrna_py_to_array(ptr, prop, data, value, error_prefix) == 
-1) {
                        return -1;
                }
        }
@@ -1767,8 +1763,8 @@
 
        if (totdim > 1) {
                /* char error_str[512]; */
-               if (!pyrna_py_to_array_index(&self->ptr, self->prop, 
self->arraydim, self->arrayoffset, index, value, "")) {
-                       /* PyErr_SetString(PyExc_AttributeError, error_str); */
+               if (pyrna_py_to_array_index(&self->ptr, self->prop, 
self->arraydim, self->arrayoffset, index, value, "") == -1) {
+                       /* error is set */
                        ret= -1;
                }
        }

Modified: trunk/blender/source/blender/python/intern/bpy_rna_array.c
===================================================================
--- trunk/blender/source/blender/python/intern/bpy_rna_array.c  2011-06-17 
00:39:59 UTC (rev 37574)
+++ trunk/blender/source/blender/python/intern/bpy_rna_array.c  2011-06-17 
02:22:38 UTC (rev 37575)
@@ -68,15 +68,19 @@
                /* check that a sequence contains dimsize[dim] items */
                const int seq_size= PySequence_Size(seq);
                if(seq_size == -1) {
-                       PyErr_Format(PyExc_ValueError, "%s sequence expected at 
dimension %d, not %s", error_prefix, (int)dim + 1, Py_TYPE(seq)->tp_name);
-                       return 0;
+                       PyErr_Format(PyExc_ValueError, "%s sequence expected at 
dimension %d, not '%s'", error_prefix, (int)dim + 1, Py_TYPE(seq)->tp_name);
+                       return -1;
                }
                for (i= 0; i < seq_size; i++) {
                        PyObject *item;
                        int ok= 1;
                        item= PySequence_GetItem(seq, i);
 
-                       if (!PySequence_Check(item)) {
+                       if(item == NULL) {
+                               PyErr_Format(PyExc_TypeError, "%s sequence type 
'%s' failed to retrieve index %d", error_prefix, Py_TYPE(seq)->tp_name, i);
+                               ok= 0;
+                       }
+                       else if (!PySequence_Check(item)) {
                                /* BLI_snprintf(error_str, error_str_size, 
"expected a sequence of %s", item_type_str); */
                                PyErr_Format(PyExc_TypeError, "%s expected a 
sequence of %s, not %s", error_prefix, item_type_str, Py_TYPE(item)->tp_name);
                                ok= 0;
@@ -91,39 +95,43 @@
                                PyErr_Format(PyExc_ValueError, "%s sequences of 
dimension %d should contain %d items", error_prefix, (int)dim + 1, 
(int)dimsize[dim + 1]);
                                ok= 0;
                        }
-                       else if (!validate_array_type(item, dim + 1, totdim, 
dimsize, check_item_type, item_type_str, error_prefix)) {
+                       else if (validate_array_type(item, dim + 1, totdim, 
dimsize, check_item_type, item_type_str, error_prefix) == -1) {
                                ok= 0;
                        }
 
-                       Py_DECREF(item);
+                       Py_XDECREF(item);
 
                        if (!ok)
-                               return 0;
+                               return -1;
                }
        }
        else {
                /* check that items are of correct type */
                const int seq_size= PySequence_Size(seq);
                if(seq_size == -1) {
-                       PyErr_Format(PyExc_ValueError, "%s sequence expected at 
dimension %d, not %s", error_prefix, (int)dim + 1, Py_TYPE(seq)->tp_name);
-                       return 0;
+                       PyErr_Format(PyExc_ValueError, "%s sequence expected at 
dimension %d, not '%s'", error_prefix, (int)dim + 1, Py_TYPE(seq)->tp_name);
+                       return -1;
                }
                for (i= 0; i < seq_size; i++) {
                        PyObject *item= PySequence_GetItem(seq, i);
 
-                       if (!check_item_type(item)) {
+                       if(item == NULL) {
+                               PyErr_Format(PyExc_TypeError, "%s sequence type 
'%s' failed to retrieve index %d", error_prefix, Py_TYPE(seq)->tp_name, i);
+                               return -1;
+                       }
+                       else if (!check_item_type(item)) {
                                Py_DECREF(item);
 
                                /* BLI_snprintf(error_str, error_str_size, 
"sequence items should be of type %s", item_type_str); */
                                PyErr_Format(PyExc_TypeError, "%s expected 
sequence items of type %s, not %s", error_prefix, item_type_str, 
Py_TYPE(item)->tp_name);
-                               return 0;
+                               return -1;
                        }
 
                        Py_DECREF(item);
                }
        }
 
-       return 1;
+       return 0; /* ok */
 }
 
 /* Returns the number of items in a single- or multi-dimensional sequence. */
@@ -136,8 +144,21 @@
                int i;
                for (i= 0; i < seq_size; i++) {
                        PyObject *item= PySequence_GetItem(seq, i);
-                       totitem += count_items(item, dim - 1);
-                       Py_DECREF(item);
+                       if(item) {
+                               const int tot= count_items(item, dim - 1);
+                               Py_DECREF(item);
+                               if(tot != -1) {
+                                       totitem += tot;
+                               }
+                               else {
+                                       totitem= -1;
+                                       break;
+                               }
+                       }
+                       else {
+                               totitem= -1;
+                               break;
+                       }
                }
        }
        else {
@@ -156,18 +177,22 @@
        totdim= RNA_property_array_dimension(ptr, prop, dimsize);
        tot= count_items(rvalue, totdim - lvalue_dim);
 
-       if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
+       if(tot == -1) {
+               PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, error 
validating the sequence length", error_prefix, 
RNA_struct_identifier(ptr->type), RNA_property_identifier(prop));
+               return -1;
+       }
+       else if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
                if (RNA_property_array_length(ptr, prop) != tot) {
 #if 0
                        /* length is flexible */
                        if (!RNA_property_dynamic_array_set_length(ptr, prop, 
tot)) {
                                /* BLI_snprintf(error_str, error_str_size, 
"%s.%s: array length cannot be changed to %d", 
RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */
                                PyErr_Format(PyExc_ValueError, "%s %s.%s: array 
length cannot be changed to %d", error_prefix, 
RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot);
-                               return 0;
+                               return -1;
                        }
 #else
                        *totitem= tot;
-                       return 1;
+                       return 0;
 
 #endif
                }
@@ -205,13 +230,13 @@
                if (tot != len) {
                        /* BLI_snprintf(error_str, error_str_size, "sequence 
must have length of %d", len); */
                        PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, 
sequence must have %d items total, not %d", error_prefix, 
RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), len, tot);
-                       return 0;
+                       return -1;
                }
        }
 
        *totitem= len;
 
-       return 1;
+       return 0;
 }
 
 static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA 
*prop, int lvalue_dim, ItemTypeCheckFunc check_item_type, const char 
*item_type_str, int *totitem, const char *error_prefix)
@@ -221,8 +246,8 @@
 
        /* validate type first because length validation may modify property 
array length */
 
-       if (!validate_array_type(rvalue, lvalue_dim, totdim, dimsize, 
check_item_type, item_type_str, error_prefix))
-               return 0;
+       if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, 
check_item_type, item_type_str, error_prefix) == -1)
+               return -1;
 
        return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, 
error_prefix);
 }
@@ -250,25 +275,39 @@
        int totdim= RNA_property_array_dimension(ptr, prop, NULL);
        const int seq_size= PySequence_Size(seq);
 
-       assert(seq_size != -1);
+       /* General note for 'data' being NULL or PySequence_GetItem() failing.
+        *
+        * This should never be NULL since we validated it, _but_ some triky 
python
+        * developer could write their own sequence type which succeeds on
+        * validating but fails later somehow, so include checks for safety. */
 
-       for (i= 0; i < seq_size; i++) {
+       if(seq_size == -1) {
+               return NULL;
+       }
+
+       for (i= 0; (i < seq_size) && data; i++) {
                PyObject *item= PySequence_GetItem(seq, i);
+               if(item) {
+                       if (dim + 1 < totdim) {
+                               data= copy_values(item, ptr, prop, dim + 1, 
data, item_size, index, convert_item, rna_set_index);
+                       }
+                       else {
+                               data= copy_value_single(item, ptr, prop, data, 
item_size, index, convert_item, rna_set_index);
+                       }
 
-               if (dim + 1 < totdim) {
-                       data= copy_values(item, ptr, prop, dim + 1, data, 
item_size, index, convert_item, rna_set_index);
+                       Py_DECREF(item);
+
+                       /* data may be NULL, but the for loop checks */
                }
                else {
-                       data= copy_value_single(item, ptr, prop, data, 
item_size, index, convert_item, rna_set_index);
+                       return NULL;
                }
-
-               Py_DECREF(item);
        }
 
        return data;
 }
 
-static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char 
*param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int 
item_size, ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const 
char *error_prefix)
+static int py_to_array(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, char 
*param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int 
item_size, ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const 
char *error_prefix)
 {
        /*int totdim, dim_size[MAX_ARRAY_DIMENSION];*/
        int totitem;
@@ -276,8 +315,8 @@
 
        /*totdim= RNA_property_array_dimension(ptr, prop, dim_size);*/ 
/*UNUSED*/
 
-       if (!validate_array(py, ptr, prop, 0, check_item_type, item_type_str, 
&totitem, error_prefix)) {
-               return 0;
+       if (validate_array(seq, ptr, prop, 0, check_item_type, item_type_str, 
&totitem, error_prefix) == -1) {
+               return -1;
        }
 
        if (totitem) {
@@ -297,16 +336,26 @@
                        data= PyMem_MALLOC(item_size * totitem);
                }
 
-               copy_values(py, ptr, prop, 0, data, item_size, NULL, 
convert_item, NULL);
+               /* will only fail in very rare cases since we already validated 
the
+                * python data, the check here is mainly for completeness. */
+               if(copy_values(seq, ptr, prop, 0, data, item_size, NULL, 
convert_item, NULL) != NULL) {
+                       if (param_data==NULL) {
+                               /* NULL can only pass through in case RNA 
property arraylength is 0 (impossible?) */
+                               rna_set_array(ptr, prop, data);
+                               PyMem_FREE(data);
+                       }
+               }
+               else {
+                       if (param_data==NULL) {
+                               PyMem_FREE(data);
+                       }
 
-               if (param_data==NULL) {
-                       /* NULL can only pass through in case RNA property 
arraylength is 0 (impossible?) */
-                       rna_set_array(ptr, prop, data);
-                       PyMem_FREE(data);
+                       PyErr_Format(PyExc_TypeError, "%s internal error 
parsing sequence of type '%s' after successful validation", error_prefix, 
Py_TYPE(seq)->tp_name);
+                       return -1;

@@ Diff output truncated at 10240 characters. @@
_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to