Fix T100026: crash with zero-sized attributes
The problem was that zero-sized and non-existant attributes were handled the same in some parts of the attribute API, which led to unexpected behavior. The solution is to properly differentiate the case when an attribute does not exist and when it is just empty (because the geometry is empty). Differential Revision: https://developer.blender.org/D15557
This commit is contained in:
parent
84a3ff63d0
commit
6e5eb46d73
Notes:
blender-bot
2023-02-14 05:51:15 +01:00
Referenced by commit ced56dbc53
, Fix: Restore fix for empty attributes after recent commit
Referenced by issue #100026, Crash on new Curve System with Geometry Nodes
|
@ -214,36 +214,33 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr
|
|||
const int domain_num,
|
||||
const AttributeInit &initializer)
|
||||
{
|
||||
const int old_layer_num = custom_data.totlayer;
|
||||
switch (initializer.type) {
|
||||
case AttributeInit::Type::Default: {
|
||||
void *data = add_generic_custom_data_layer(
|
||||
add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id);
|
||||
return data != nullptr;
|
||||
break;
|
||||
}
|
||||
case AttributeInit::Type::VArray: {
|
||||
void *data = add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id);
|
||||
if (data == nullptr) {
|
||||
return false;
|
||||
if (data != nullptr) {
|
||||
const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
|
||||
varray.materialize_to_uninitialized(varray.index_range(), data);
|
||||
}
|
||||
const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
|
||||
varray.materialize_to_uninitialized(varray.index_range(), data);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case AttributeInit::Type::MoveArray: {
|
||||
void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
|
||||
void *data = add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_ASSIGN, source_data, domain_num, attribute_id);
|
||||
if (data == nullptr) {
|
||||
if (source_data != nullptr && data == nullptr) {
|
||||
MEM_freeN(source_data);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
return old_layer_num < custom_data.totlayer;
|
||||
}
|
||||
|
||||
static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer,
|
||||
|
@ -265,17 +262,25 @@ GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const void *owner) cons
|
|||
return {};
|
||||
}
|
||||
|
||||
const void *data;
|
||||
if (stored_as_named_attribute_) {
|
||||
data = CustomData_get_layer_named(custom_data, stored_type_, name_.c_str());
|
||||
const void *data = nullptr;
|
||||
bool found_attribute = false;
|
||||
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
|
||||
if (stored_as_named_attribute_) {
|
||||
if (layer.name == name_) {
|
||||
data = layer.data;
|
||||
found_attribute = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (layer.type == stored_type_) {
|
||||
data = layer.data;
|
||||
found_attribute = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
data = CustomData_get_layer(custom_data, stored_type_);
|
||||
}
|
||||
if (data == nullptr) {
|
||||
if (!found_attribute) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const int element_num = custom_data_access_.get_element_num(owner);
|
||||
return as_read_attribute_(data, element_num);
|
||||
}
|
||||
|
@ -291,31 +296,42 @@ GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(void *owner)
|
|||
}
|
||||
const int element_num = custom_data_access_.get_element_num(owner);
|
||||
|
||||
void *data;
|
||||
if (stored_as_named_attribute_) {
|
||||
data = CustomData_get_layer_named(custom_data, stored_type_, name_.c_str());
|
||||
void *data = nullptr;
|
||||
bool found_attribute = false;
|
||||
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
|
||||
if (stored_as_named_attribute_) {
|
||||
if (layer.name == name_) {
|
||||
data = layer.data;
|
||||
found_attribute = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (layer.type == stored_type_) {
|
||||
data = layer.data;
|
||||
found_attribute = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
data = CustomData_get_layer(custom_data, stored_type_);
|
||||
}
|
||||
if (data == nullptr) {
|
||||
if (!found_attribute) {
|
||||
return {};
|
||||
}
|
||||
|
||||
void *new_data;
|
||||
if (stored_as_named_attribute_) {
|
||||
new_data = CustomData_duplicate_referenced_layer_named(
|
||||
custom_data, stored_type_, name_.c_str(), element_num);
|
||||
}
|
||||
else {
|
||||
new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, element_num);
|
||||
}
|
||||
|
||||
if (data != new_data) {
|
||||
if (custom_data_access_.update_custom_data_pointers) {
|
||||
custom_data_access_.update_custom_data_pointers(owner);
|
||||
if (data != nullptr) {
|
||||
void *new_data;
|
||||
if (stored_as_named_attribute_) {
|
||||
new_data = CustomData_duplicate_referenced_layer_named(
|
||||
custom_data, stored_type_, name_.c_str(), element_num);
|
||||
}
|
||||
else {
|
||||
new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, element_num);
|
||||
}
|
||||
|
||||
if (data != new_data) {
|
||||
if (custom_data_access_.update_custom_data_pointers) {
|
||||
custom_data_access_.update_custom_data_pointers(owner);
|
||||
}
|
||||
data = new_data;
|
||||
}
|
||||
data = new_data;
|
||||
}
|
||||
|
||||
std::function<void()> tag_modified_fn;
|
||||
|
|
Loading…
Reference in New Issue