RNA: Better enforce rules about pointers between datablocks
* Linked datablocks should not point to local datablocks. * Main datablocks should not point to non-main datablocks. This is checked now both in the poll function for UI lists, and in the pointer assignment code used by the Python API.
This commit is contained in:
parent
b5ef5c3aba
commit
a1b4d5ecc8
@ -744,6 +744,13 @@ ID *BKE_id_owner_get(ID *id, const bool debug_relationship_assert = true);
|
||||
*/
|
||||
bool BKE_id_is_editable(const Main *bmain, const ID *id);
|
||||
|
||||
/**
|
||||
* Check that a pointer from one ID to another is possible.
|
||||
*
|
||||
* Taking into account lib linking and main database membership.
|
||||
*/
|
||||
bool BKE_id_can_use_id(const ID &id_from, const ID &id_to);
|
||||
|
||||
/**
|
||||
* Returns ordered list of data-blocks for display in the UI.
|
||||
*/
|
||||
|
@ -2268,6 +2268,20 @@ bool BKE_id_is_editable(const Main *bmain, const ID *id)
|
||||
return ID_IS_EDITABLE(id) && !BKE_lib_override_library_is_system_defined(bmain, id);
|
||||
}
|
||||
|
||||
bool BKE_id_can_use_id(const ID &id_from, const ID &id_to)
|
||||
{
|
||||
/* Can't point from linked to local. */
|
||||
if (id_from.lib && !id_to.lib) {
|
||||
return false;
|
||||
}
|
||||
/* Can't point from ID in main database to one outside of it. */
|
||||
if (!(id_from.tag & LIB_TAG_NO_MAIN) && (id_to.tag & LIB_TAG_NO_MAIN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************* Datablock order in UI **************************/
|
||||
|
||||
static int *id_order_get(ID *id)
|
||||
|
@ -1269,14 +1269,28 @@ static char *rna_def_property_set_func(
|
||||
else {
|
||||
rna_print_data_get(f, dp);
|
||||
|
||||
PointerPropertyRNA *pprop = (PointerPropertyRNA *)dp->prop;
|
||||
StructRNA *type = (pprop->type) ? rna_find_struct((const char *)pprop->type) : nullptr;
|
||||
|
||||
if (prop->flag & PROP_ID_SELF_CHECK) {
|
||||
/* No pointers to self allowed. */
|
||||
rna_print_id_get(f, dp);
|
||||
fprintf(f, " if (id == value.data) {\n");
|
||||
fprintf(f, " return;\n");
|
||||
fprintf(f, " }\n");
|
||||
}
|
||||
|
||||
if (type && (type->flag & STRUCT_ID)) {
|
||||
/* Check if pointers between datablocks are allowed. */
|
||||
fprintf(f,
|
||||
" if (value.data && ptr->owner_id && value.owner_id && "
|
||||
"!BKE_id_can_use_id(*ptr->owner_id, *value.owner_id)) {\n");
|
||||
fprintf(f, " return;\n");
|
||||
fprintf(f, " }\n");
|
||||
}
|
||||
|
||||
if (prop->flag & PROP_ID_REFCOUNT) {
|
||||
/* Perform reference counting. */
|
||||
fprintf(f, "\n if (data->%s) {\n", dp->dnaname);
|
||||
fprintf(f, " id_us_min((ID *)data->%s);\n", dp->dnaname);
|
||||
fprintf(f, " }\n");
|
||||
@ -1284,14 +1298,11 @@ static char *rna_def_property_set_func(
|
||||
fprintf(f, " id_us_plus((ID *)value.data);\n");
|
||||
fprintf(f, " }\n");
|
||||
}
|
||||
else {
|
||||
PointerPropertyRNA *pprop = (PointerPropertyRNA *)dp->prop;
|
||||
StructRNA *type = (pprop->type) ? rna_find_struct((const char *)pprop->type) : nullptr;
|
||||
if (type && (type->flag & STRUCT_ID)) {
|
||||
fprintf(f, " if (value.data) {\n");
|
||||
fprintf(f, " id_lib_extern((ID *)value.data);\n");
|
||||
fprintf(f, " }\n");
|
||||
}
|
||||
else if (type && (type->flag & STRUCT_ID)) {
|
||||
/* Still mark linked data as used if not reference counting. */
|
||||
fprintf(f, " if (value.data) {\n");
|
||||
fprintf(f, " id_lib_extern((ID *)value.data);\n");
|
||||
fprintf(f, " }\n");
|
||||
}
|
||||
|
||||
fprintf(f, " *(void **)&data->%s = value.data;\n", dp->dnaname);
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "BKE_global.hh"
|
||||
#include "BKE_idprop.hh"
|
||||
#include "BKE_idtype.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_lib_override.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_node.hh"
|
||||
@ -1580,22 +1581,28 @@ bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *v
|
||||
{
|
||||
prop = rna_ensure_property(prop);
|
||||
|
||||
if (prop->type == PROP_POINTER) {
|
||||
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
|
||||
if (prop->type != PROP_POINTER) {
|
||||
printf("%s: %s is not a pointer property.\n", __func__, prop->identifier);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pprop->poll) {
|
||||
if (rna_idproperty_check(&prop, ptr)) {
|
||||
return reinterpret_cast<PropPointerPollFuncPy>(reinterpret_cast<void *>(pprop->poll))(
|
||||
ptr, *value, prop);
|
||||
}
|
||||
return pprop->poll(ptr, *value);
|
||||
}
|
||||
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
|
||||
|
||||
/* Can't point from linked to local datablock. */
|
||||
if (ptr->owner_id && value->owner_id && !BKE_id_can_use_id(*ptr->owner_id, *value->owner_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check custom poll function. */
|
||||
if (!pprop->poll) {
|
||||
return true;
|
||||
}
|
||||
|
||||
printf("%s: %s is not a pointer property.\n", __func__, prop->identifier);
|
||||
return false;
|
||||
if (rna_idproperty_check(&prop, ptr)) {
|
||||
return reinterpret_cast<PropPointerPollFuncPy>(reinterpret_cast<void *>(pprop->poll))(
|
||||
ptr, *value, prop);
|
||||
}
|
||||
return pprop->poll(ptr, *value);
|
||||
}
|
||||
|
||||
void RNA_property_enum_items_ex(bContext *C,
|
||||
|
Loading…
Reference in New Issue
Block a user