[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [37114] trunk/blender/source/blender/ python/intern/bpy_props.c: when making the C/RNA copy of the python enum, duplicate all strings since theres no guarantee python wont free them immediately after , though in practice this isn't so common.
Campbell Barton
ideasman42 at gmail.com
Fri Jun 3 06:21:42 CEST 2011
Revision: 37114
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=37114
Author: campbellbarton
Date: 2011-06-03 04:21:41 +0000 (Fri, 03 Jun 2011)
Log Message:
-----------
when making the C/RNA copy of the python enum, duplicate all strings since theres no guarantee python wont free them immediately after, though in practice this isn't so common.
Modified Paths:
--------------
trunk/blender/source/blender/python/intern/bpy_props.c
Modified: trunk/blender/source/blender/python/intern/bpy_props.c
===================================================================
--- trunk/blender/source/blender/python/intern/bpy_props.c 2011-06-03 03:19:22 UTC (rev 37113)
+++ trunk/blender/source/blender/python/intern/bpy_props.c 2011-06-03 04:21:41 UTC (rev 37114)
@@ -642,18 +642,27 @@
Py_RETURN_NONE;
}
+/* copies orig to buf, then sets orig to buf, returns copy length */
+static size_t strswapbufcpy(char *buf, const char **orig)
+{
+ const char *src= *orig;
+ char *dst= buf;
+ size_t i= 0;
+ *orig= buf;
+ while((*dst= *src)) { dst++; src++; i++; }
+ return i + 1; /* include '\0' */
+}
+
static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, int *defvalue, const short is_enum_flag)
{
-# define PREALLOC_ENUM
-
EnumPropertyItem *items;
PyObject *item;
- int seq_len, i, totitem= 0;
+ const Py_ssize_t seq_len= PySequence_Fast_GET_SIZE(seq_fast);
+ Py_ssize_t totbuf= 0;
+ int i;
short def_used= 0;
const char *def_cmp= NULL;
- seq_len= PySequence_Fast_GET_SIZE(seq_fast);
-
if(is_enum_flag) {
if(seq_len > RNA_ENUM_BITFLAG_SIZE) {
PyErr_SetString(PyExc_TypeError, "EnumProperty(...): maximum " STRINGIFY(RNA_ENUM_BITFLAG_SIZE) " members for a ENUM_FLAG type property");
@@ -683,55 +692,52 @@
/* blank value */
*defvalue= 0;
-#ifdef PREALLOC_ENUM
- items= MEM_callocN(sizeof(EnumPropertyItem) * (seq_len + 1), "RNA_enum_items_reserve");
-#endif
+ items= MEM_callocN(sizeof(EnumPropertyItem) * (seq_len + 1), "enum_items_from_py1");
for(i=0; i<seq_len; i++) {
EnumPropertyItem tmp= {0, "", 0, "", ""};
+ Py_ssize_t id_str_size;
+ Py_ssize_t name_str_size;
+ Py_ssize_t desc_str_size;
item= PySequence_Fast_GET_ITEM(seq_fast, i);
- /* this also checks for a tuple */
- if(!PyArg_ParseTuple(item, "sss", &tmp.identifier, &tmp.name, &tmp.description)) {
-#ifdef PREALLOC_ENUM
- MEM_freeN(items);
-#else
- if(items) MEM_freeN(items);
-#endif
- PyErr_SetString(PyExc_TypeError, "EnumProperty(...): expected an tuple containing (identifier, name description)");
- return NULL;
- }
+ if( (PyTuple_CheckExact(item)) &&
+ (PyTuple_GET_SIZE(item) == 3) &&
+ (tmp.identifier= _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 0), &id_str_size)) &&
+ (tmp.name= _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 1), &name_str_size)) &&
+ (tmp.description= _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 2), &desc_str_size))
+ ) {
+ if(is_enum_flag) {
+ tmp.value= 1<<i;
- if(is_enum_flag) {
- tmp.value= 1<<i;
+ if(def && PySet_Contains(def, PyTuple_GET_ITEM(item, 0))) {
+ *defvalue |= tmp.value;
+ def_used++;
+ }
+ }
+ else {
+ tmp.value= i;
- if(def && PySet_Contains(def, PyTuple_GET_ITEM(item, 0))) {
- *defvalue |= tmp.value;
- def_used++;
+ if(def && def_used == 0 && strcmp(def_cmp, tmp.identifier)==0) {
+ *defvalue= tmp.value;
+ def_used++; /* only ever 1 */
+ }
}
+
+ items[i]= tmp;
+
+ /* calculate combine string length */
+ totbuf += id_str_size + name_str_size + desc_str_size + 3; /* 3 is for '\0's */
}
else {
- tmp.value= i;
+ MEM_freeN(items);
+ PyErr_SetString(PyExc_TypeError, "EnumProperty(...): expected an tuple containing (identifier, name description)");
+ return NULL;
+ }
- if(def && def_used == 0 && strcmp(def_cmp, tmp.identifier)==0) {
- *defvalue= tmp.value;
- def_used++; /* only ever 1 */
- }
- }
-#ifdef PREALLOC_ENUM
- items[i]= tmp;
-#else
- RNA_enum_item_add(&items, &totitem, &tmp);
-#endif
}
-#ifdef PREALLOC_ENUM
- /* do nohing */
-#else
- RNA_enum_item_end(&items, &totitem);
-#endif
-
if(is_enum_flag) {
/* strict check that all set members were used */
if(def && def_used != PySet_GET_SIZE(def)) {
@@ -754,9 +760,25 @@
}
}
+ /* this would all work perfectly _but_ the python strings may be freed
+ * immediately after use, so we need to duplicate them, ugh.
+ * annoying because it works most of the time without this. */
+ {
+ EnumPropertyItem *items_dup= MEM_mallocN((sizeof(EnumPropertyItem) * (seq_len + 1)) + (sizeof(char) * totbuf), "enum_items_from_py2");
+ EnumPropertyItem *items_ptr= items_dup;
+ char *buf= ((char *)items_dup) + (sizeof(EnumPropertyItem) * (seq_len + 1));
+ memcpy(items_dup, items, sizeof(EnumPropertyItem) * (seq_len + 1));
+ for(i=0; i<seq_len; i++, items_ptr++) {
+ buf += strswapbufcpy(buf, &items_ptr->identifier);
+ buf += strswapbufcpy(buf, &items_ptr->name);
+ buf += strswapbufcpy(buf, &items_ptr->description);
+ }
+ MEM_freeN(items);
+ items=items_dup;
+ }
+ /* end string duplication */
+
return items;
-
-# undef PREALLOC_ENUM
}
static EnumPropertyItem *bpy_props_enum_itemf(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int *free)
More information about the Bf-blender-cvs
mailing list