GPv3: Port frame_clean_duplicate operator #116655

Open
Abdelrahman Said wants to merge 28 commits from amsaid1989/blender:gpv3-delete-duplicate-frames into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
2 changed files with 178 additions and 0 deletions

View File

@ -5892,6 +5892,7 @@ class VIEW3D_MT_edit_greasepencil_cleanup(Menu):
layout = self.layout
layout.operator("grease_pencil.clean_loose")
layout.operator("grease_pencil.frame_clean_duplicate")
class VIEW3D_MT_edit_greasepencil(Menu):

View File

@ -6,6 +6,7 @@
* \ingroup edgreasepencil
*/
#include "BKE_curves.hh"
#include "BLI_map.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_utildefines.h"
@ -410,6 +411,160 @@ static int insert_blank_frame_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static bool attributes_varrays_not_equal(const bke::GAttributeReader &attrs_a,
const bke::GAttributeReader &attrs_b)
{
return (attrs_a.varray.size() != attrs_b.varray.size() ||
attrs_a.varray.type() != attrs_b.varray.type());
}
static bool attributes_varrays_span_data_equal(const bke::GAttributeReader &attrs_a,
const bke::GAttributeReader &attrs_b)
{
if (attrs_a.varray.is_span() && attrs_b.varray.is_span()) {
const GSpan attrs_span_a = attrs_a.varray.get_internal_span();
const GSpan attrs_span_b = attrs_b.varray.get_internal_span();
amsaid1989 marked this conversation as resolved Outdated

You have check size few lines above, right?

You have check size few lines above, right?

Removed this extra size check

Removed this extra size check
if (attrs_span_a.data() == attrs_span_b.data()) {
return true;
}
}
amsaid1989 marked this conversation as resolved Outdated

Should be false.

Should be false.

Done

Done
return false;
}
PratikPB2123 marked this conversation as resolved Outdated

Not sure why this check is needed.

Not sure why this check is needed.

In case lists of attributes are different, i think this is reasonable to treat such curves as different..

In case lists of attributes are different, i think this is reasonable to treat such curves as different..

I will leave this check as is since @mod_moder agrees it's needed

I will leave this check as is since @mod_moder agrees it's needed

I see, make sense.

I see, make sense.
template<typename T>
static bool attributes_elements_are_equal(const VArray<T> &attributes_a,
const VArray<T> &attributes_b)
{
const std::optional<T> value_a = attributes_a.get_if_single();
const std::optional<T> value_b = attributes_b.get_if_single();
if (value_a.has_value() && value_b.has_value()) {
return value_a.value() == value_b.value();
}
const VArraySpan attrs_span_a = attributes_a;
const VArraySpan attrs_span_b = attributes_b;
return std::equal(
attrs_span_a.begin(), attrs_span_a.end(), attrs_span_b.begin(), attrs_span_b.end());
}
static bool curves_geometry_is_equal(const bke::CurvesGeometry &curves_a,
const bke::CurvesGeometry &curves_b)
{
using namespace blender::bke;
if (curves_a.points_num() == 0 && curves_b.points_num() == 0) {
return true;
}
if (curves_a.curves_num() != curves_b.curves_num() ||
curves_a.points_num() != curves_b.points_num() || curves_a.offsets() != curves_b.offsets())
{
return false;
amsaid1989 marked this conversation as resolved Outdated

here offset() memory is garbage if curves has empty drawing. This would lead to crash. Just add one if condition before this to return true when both the curves has 0 points:

  if ((curves_a.points_num() == 0) && (curves_b.points_num() == 0)) {
    return true;
  }
here offset() memory is garbage if curves has empty drawing. This would lead to crash. Just add one if condition before this to return true when both the curves has 0 points: ``` if ((curves_a.points_num() == 0) && (curves_b.points_num() == 0)) { return true; } ```

Fixed it. Thank you very much for catching it

Fixed it. Thank you very much for catching it
}
const AttributeAccessor attributes_a = curves_a.attributes();
const AttributeAccessor attributes_b = curves_b.attributes();
amsaid1989 marked this conversation as resolved Outdated

not sure if this is needed. You could just call std::equal() in current lamda too, no?
I might be misunderstanding something

not sure if this is needed. You could just call `std::equal()` in current lamda too, no? I might be misunderstanding something

This was implemented based on guidance I got in blender.chat from @mod_moder when I started working on this. This is what was recommended to me to compare all the attributes.

This was implemented based on guidance I got in [blender.chat](blender.chat) from @mod_moder when I started working on this. This is what was recommended to me to compare all the attributes.
const Set<AttributeIDRef> ids_a = attributes_a.all_ids();
const Set<AttributeIDRef> ids_b = attributes_b.all_ids();
if (ids_a != ids_b) {
return false;
}
for (const AttributeIDRef &id : ids_a) {
GAttributeReader attrs_a = attributes_a.lookup(id);
GAttributeReader attrs_b = attributes_b.lookup(id);
if (attributes_varrays_not_equal(attrs_a, attrs_b)) {
return false;
}
amsaid1989 marked this conversation as resolved Outdated
if (attributes_varrays_are_equal(attrs_a, attrs_b)) {
  return true;
}
```Cpp if (attributes_varrays_are_equal(attrs_a, attrs_b)) { return true; } ```

Done

Done
if (attributes_varrays_span_data_equal(attrs_a, attrs_b)) {
return true;
}
bool attributes_are_equal = true;
amsaid1989 marked this conversation as resolved Outdated

attrs_equal -> attributes_are_equal

`attrs_equal` -> `attributes_are_equal`

Renamed the variable

Renamed the variable
attribute_math::convert_to_static_type(attrs_a.varray.type(), [&](auto dummy) {
using T = decltype(dummy);
amsaid1989 marked this conversation as resolved Outdated

Right now this is incorrect.
if (attributes_varrays_are_equal(attrs_a, attrs_b)) { is used for early skip if this is possible (arrays is actually is the same data segment in memory).
But right now you also have to check if this is obviously impossible (different types or sizes).
If you'll do this cast for attributes with different sizes/types, this will be UB and assertion in debug.
You need to explicitly check if attributes_varrays_not_equal before of this.
And additional cleanup comment: upcast to static type for attributes should be on the caller, not in the template method.

Right now this is incorrect. `if (attributes_varrays_are_equal(attrs_a, attrs_b)) {` is used for early skip if this is possible (arrays is actually is the same data segment in memory). But right now you also have to check if this is obviously impossible (different types or sizes). If you'll do this cast for attributes with different sizes/types, this will be UB and assertion in debug. You need to explicitly check if `attributes_varrays_not_equal` before of this. And additional cleanup comment: upcast to static type for attributes should be on the caller, not in the template method.

@mod_moder I have addressed your comments about the varrays check.

Renamed attributes_varrays_are_equal to attributes_varrays_span_data_equal and updated it to this:

static bool attributes_varrays_span_data_equal(const bke::GAttributeReader &attrs_a,
                                         const bke::GAttributeReader &attrs_b)
{
  if (attrs_a.varray.is_span() && attrs_b.varray.is_span()) {
    const GSpan attrs_span_a = attrs_a.varray.get_internal_span();
    const GSpan attrs_span_b = attrs_b.varray.get_internal_span();

    if (attrs_span_a.data() == attrs_span_b.data()) {
      return true;
    }
  }

  return false;
}

Then, I added attributes_varrays_not_equal which is implemented as follows:

static bool attributes_varrays_not_equal(const bke::GAttributeReader &attrs_a,
                                         const bke::GAttributeReader &attrs_b)
{
  return (attrs_a.varray.size() != attrs_b.varray.size() ||
          attrs_a.varray.type() != attrs_b.varray.type());
}

These 2 functions are then used like this:

if (attributes_varrays_span_data_equal(attrs_a, attrs_b)) {
	return true;
}

if (attributes_varrays_not_equal(attrs_a, attrs_b)) {
	return false;
}

Does this make more sense?

@mod_moder I have addressed your comments about the varrays check. Renamed `attributes_varrays_are_equal` to `attributes_varrays_span_data_equal` and updated it to this: ```cpp static bool attributes_varrays_span_data_equal(const bke::GAttributeReader &attrs_a, const bke::GAttributeReader &attrs_b) { if (attrs_a.varray.is_span() && attrs_b.varray.is_span()) { const GSpan attrs_span_a = attrs_a.varray.get_internal_span(); const GSpan attrs_span_b = attrs_b.varray.get_internal_span(); if (attrs_span_a.data() == attrs_span_b.data()) { return true; } } return false; } ``` Then, I added `attributes_varrays_not_equal` which is implemented as follows: ```cpp static bool attributes_varrays_not_equal(const bke::GAttributeReader &attrs_a, const bke::GAttributeReader &attrs_b) { return (attrs_a.varray.size() != attrs_b.varray.size() || attrs_a.varray.type() != attrs_b.varray.type()); } ``` These 2 functions are then used like this: ```cpp if (attributes_varrays_span_data_equal(attrs_a, attrs_b)) { return true; } if (attributes_varrays_not_equal(attrs_a, attrs_b)) { return false; } ``` Does this make more sense?

And additional cleanup comment: upcast to static type for attributes should be on the caller, not in the template method.

Regarding this, I would like to confirm that I understand you correctly.

You want to change the lambda in convert_to_static_type to this:

attribute_math::convert_to_static_type(attrs_a.varray.type(), [&](auto dummy) {
  using T = decltype(dummy);

  const VArray attributes_a = attrs_a.varray.typed<T>();
  const VArray attributes_b = attrs_b.varray.typed<T>();

  attributes_are_equal = attributes_elements_are_equal(attributes_a, attributes_b);
});

And change the attributes_elements_are_equal to the following:

template<typename T>
static bool attributes_elements_are_equal(const VArray<T> &attributes_a,
                                          const VArray<T> &attributes_b)
{
  const std::optional<T> value_a = attributes_a.get_if_single();
  const std::optional<T> value_b = attributes_b.get_if_single();
  if (value_a.has_value() && value_b.has_value()) {
    return value_a.value() == value_b.value();
  }

  const VArraySpan attrs_span_a = attributes_a;
  const VArraySpan attrs_span_b = attributes_b;

  return std::equal(
      attrs_span_a.begin(), attrs_span_a.end(), attrs_span_b.begin(), attrs_span_b.end());
}
> And additional cleanup comment: upcast to static type for attributes should be on the caller, not in the template method. Regarding this, I would like to confirm that I understand you correctly. You want to change the lambda in `convert_to_static_type` to this: ```cpp attribute_math::convert_to_static_type(attrs_a.varray.type(), [&](auto dummy) { using T = decltype(dummy); const VArray attributes_a = attrs_a.varray.typed<T>(); const VArray attributes_b = attrs_b.varray.typed<T>(); attributes_are_equal = attributes_elements_are_equal(attributes_a, attributes_b); }); ``` And change the `attributes_elements_are_equal` to the following: ```cpp template<typename T> static bool attributes_elements_are_equal(const VArray<T> &attributes_a, const VArray<T> &attributes_b) { const std::optional<T> value_a = attributes_a.get_if_single(); const std::optional<T> value_b = attributes_b.get_if_single(); if (value_a.has_value() && value_b.has_value()) { return value_a.value() == value_b.value(); } const VArraySpan attrs_span_a = attributes_a; const VArraySpan attrs_span_b = attributes_b; return std::equal( attrs_span_a.begin(), attrs_span_a.end(), attrs_span_b.begin(), attrs_span_b.end()); } ```

Order of attributes_varrays_span_data_equal and attributes_varrays_not_equal can be changed (first - early skip of wrong types and sizes, and next early confirm that data is the same). This looks good now.

Regarding this, I would like to confirm that I understand you correctly.

Yes, this is correct.

Order of `attributes_varrays_span_data_equal` and `attributes_varrays_not_equal` can be changed (first - early skip of wrong types and sizes, and next early confirm that data is the same). This looks good now. > Regarding this, I would like to confirm that I understand you correctly. Yes, this is correct.

Great.. Thank you very much. Updated the PR.

Great.. Thank you very much. Updated the PR.
amsaid1989 marked this conversation as resolved Outdated

get_editable_drawing_at accepts layer reference. So pass *layer

`get_editable_drawing_at` accepts layer reference. So pass `*layer`
const VArray attributes_a = attrs_a.varray.typed<T>();
amsaid1989 marked this conversation as resolved Outdated

same as above

same as above

Updated all uses of get_editable_drawing_at to pass a Layer & instead of Layer *

Updated all uses of `get_editable_drawing_at` to pass a `Layer &` instead of `Layer *`
const VArray attributes_b = attrs_b.varray.typed<T>();
attributes_are_equal = attributes_elements_are_equal(attributes_a, attributes_b);
});
if (!attributes_are_equal) {
return false;
}
}
return true;
}
static int frame_clean_duplicate_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
amsaid1989 marked this conversation as resolved Outdated

wouldn't get_editable_drawing_at work here?

wouldn't `get_editable_drawing_at` work here?

You're right.. get_editable_drawing_at works. Updated it

You're right.. `get_editable_drawing_at` works. Updated it
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
amsaid1989 marked this conversation as resolved Outdated

same as above.

Also names can be improved. eg: curves and curves_next

same as above. Also names can be improved. eg: `curves` and `curves_next`

Switched to get_editable_drawing_at and renamed the variables

Switched to `get_editable_drawing_at` and renamed the variables
const bool selected = RNA_boolean_get(op->ptr, "selected");
bool changed = false;
for (Layer *layer : grease_pencil.layers_for_write()) {
if (!layer->is_editable()) {
amsaid1989 marked this conversation as resolved Outdated

Vector<FramesMapKey> frames_to_delete;

`Vector<FramesMapKey> frames_to_delete;`

Done

Done
continue;
}
const Span<FramesMapKey> &keys = layer->sorted_keys();
Vector<FramesMapKey> frames_to_delete;
mod_moder marked this conversation as resolved Outdated

for (size_t i = 0; i < keys.size(); ++i) { and if (i + 1 >= keys.size()) {
->
const int i : keys.index_range().drop_front(1)

.... ?

`for (size_t i = 0; i < keys.size(); ++i) {` and `if (i + 1 >= keys.size()) {` -> `const int i : keys.index_range().drop_front(1)` .... ?

I needed const int i : keys.index_range().drop_back(1) instead of const int i : keys.index_range().drop_front(1)

I needed `const int i : keys.index_range().drop_back(1)` instead of `const int i : keys.index_range().drop_front(1)`
for (const int i : keys.index_range().drop_back(1)) {
const FramesMapKey current = keys[i];
PratikPB2123 marked this conversation as resolved Outdated

grease_pencil.remove_frames()

`grease_pencil.remove_frames()`

When I try to use this grease_pencil.remove_frames(*layer, frames_to_delete); I get a crash. I ran Blender in a debugger to see if I can find what is causing the crash, but I haven't figured out the reason. I am sure I am missing something with this being my first time working with Blender's code. This is the output I get in the terminal after running the test file I am using. I can't see what might be causing the problem so I thought I would share it here in case someone can figure it out.

Traceback (most recent call last):
  File "/home/abdelrahman/.config/blender/4.1/scripts/addons/bone_layer_manager/constraint_operators.py", line 472, in poll
    idx = cbone.constraint_active_index
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'constraint_active_index'
Traceback (most recent call last):
  File "/home/abdelrahman/.config/blender/4.1/scripts/addons/bone_layer_manager/constraint_operators.py", line 370, in poll
    return len(bone.constraints) > 0 and len(context.selected_pose_bones) > 1
               ^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'constraints'
Traceback (most recent call last):
  File "/home/abdelrahman/.config/blender/4.1/scripts/addons/bone_layer_manager/constraint_operators.py", line 404, in poll
    return len(bone.constraints) > 0 and len(context.selected_pose_bones) > 1
               ^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'constraints'
Traceback (most recent call last):
  File "/home/abdelrahman/.config/blender/4.1/scripts/addons/bone_layer_manager/constraint_operators.py", line 443, in poll
    return len(bone.constraints) > 0 and len(context.selected_pose_bones) > 1
               ^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'constraints'
Traceback (most recent call last):
  File "/home/abdelrahman/.config/blender/4.1/scripts/addons/bone_layer_manager/constraint_operators.py", line 260, in poll
    return len(bone.constraints) > 0 and len(context.selected_pose_bones) > 0
               ^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'constraints'
=================================================================
==1796374==ERROR: AddressSanitizer: heap-use-after-free on address 0x60c000027c40 at pc 0x0000047e8a4d bp 0x7fa4ffff03d0 sp 0x7fa4ffff03c0
READ of size 8 at 0x60c000027c40 thread T18
    #0 0x47e8a4c in MEM_lockfree_freeN /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/intern/mallocn_lockfree_impl.c:98
    #1 0x374bfe9 in free_layer_data /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2150
    #2 0x377b79e in CustomDataLayerImplicitSharing::delete_self_with_data() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2312
    #3 0xa5ff14 in blender::ImplicitSharingInfo::remove_user_and_delete_if_last() const /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenlib/BLI_implicit_sharing.hh:145
    #4 0x3750959 in customData_free_layer__internal /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2478
    #5 0x3750cc3 in CustomData_free(CustomData*, int) /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2500
    #6 0x35f7df0 in blender::bke::CurvesGeometry::~CurvesGeometry() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/curves_geometry.cc:174
    #7 0xac1657 in blender::bke::greasepencil::Drawing::~Drawing() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:300
    #8 0xb02cb8 in void MEM_delete<blender::bke::greasepencil::Drawing>(blender::bke::greasepencil::Drawing const*) /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/MEM_guardedalloc.h:292
    #9 0xae30f9 in free_drawing_array /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:2359
    #10 0xabf9f7 in grease_pencil_free_data /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:132
    #11 0xdbf343 in BKE_libblock_free_datablock /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/lib_id_delete.cc:77
    #12 0x46a3088 in blender::deg::deg_free_copy_on_write_datablock(ID*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:1017
    #13 0x46a26fd in blender::deg::deg_update_copy_on_write_datablock(blender::deg::Depsgraph const*, blender::deg::IDNode const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:896
    #14 0x46a35e3 in blender::deg::deg_evaluate_copy_on_write(Depsgraph*, blender::deg::IDNode const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:1032
    #15 0x4729aa1 in operator() /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc:182
    #16 0x4781e16 in __invoke_impl<void, blender::deg::DepsgraphNodeBuilder::add_id_node(ID*)::<lambda(Depsgraph*)>&, Depsgraph*> /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/invoke.h:61
    #17 0x4777ccc in __invoke_r<void, blender::deg::DepsgraphNodeBuilder::add_id_node(ID*)::<lambda(Depsgraph*)>&, Depsgraph*> /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/invoke.h:111
    #18 0x477177f in _M_invoke /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/std_function.h:290
    #19 0x469a772 in std::function<void (Depsgraph*)>::operator()(Depsgraph*) const /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/std_function.h:591
    #20 0x4694a81 in evaluate_node /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval.cc:102
    #21 0x4694ec2 in deg_task_run_func /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval.cc:119
    #22 0x45170de in Task::operator()() const /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenlib/intern/task_pool.cc:166
    #23 0x451c02e in tbb::internal::function_task<Task>::execute() /home/abdelrahman/Sources/programming/blender/lib/linux_x86_64/tbb/include/tbb/task.h:1059
    #24 0x7fa55a59f5b4 in tbb::internal::custom_scheduler<tbb::internal::IntelSchedulerTraits>::process_bypass_loop(tbb::internal::context_guard_helper<false>&, tbb::task*, long) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x2a5b4) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb)
    #25 0x7fa55a59f8f2 in tbb::internal::custom_scheduler<tbb::internal::IntelSchedulerTraits>::local_wait_for_all(tbb::task&, tbb::task*) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x2a8f2) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb)
    #26 0x7fa55a587776 in tbb::internal::arena::process(tbb::internal::generic_scheduler&) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x12776) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb)
    #27 0x7fa55a595f9f in tbb::internal::market::process(rml::job&) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x20f9f) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb)
    #28 0x7fa55a599d0d in tbb::internal::rml::private_worker::run() (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x24d0d) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb)
    #29 0x7fa55a599f88 in tbb::internal::rml::private_worker::thread_routine(void*) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x24f88) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb)
    #30 0x7fa54f8aa9ea  (/usr/lib/libc.so.6+0x8c9ea) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)
    #31 0x7fa54f92e7cb  (/usr/lib/libc.so.6+0x1107cb) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)

0x60c000027c40 is located 0 bytes inside of 128-byte region [0x60c000027c40,0x60c000027cc0)
freed by thread T18 here:
    #0 0x7fa559edfdb2 in __interceptor_free /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:52
    #1 0x47e8ce9 in MEM_lockfree_freeN /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/intern/mallocn_lockfree_impl.c:110
    #2 0x374bfe9 in free_layer_data /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2150
    #3 0x377b79e in CustomDataLayerImplicitSharing::delete_self_with_data() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2312
    #4 0xa5ff14 in blender::ImplicitSharingInfo::remove_user_and_delete_if_last() const /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenlib/BLI_implicit_sharing.hh:145
    #5 0x3750959 in customData_free_layer__internal /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2478
    #6 0x3750cc3 in CustomData_free(CustomData*, int) /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2500
    #7 0x35f7df0 in blender::bke::CurvesGeometry::~CurvesGeometry() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/curves_geometry.cc:174
    #8 0xac1657 in blender::bke::greasepencil::Drawing::~Drawing() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:300
    #9 0xb02cb8 in void MEM_delete<blender::bke::greasepencil::Drawing>(blender::bke::greasepencil::Drawing const*) /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/MEM_guardedalloc.h:292
    #10 0xae30f9 in free_drawing_array /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:2359
    #11 0xabf9f7 in grease_pencil_free_data /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:132
    #12 0xdbf343 in BKE_libblock_free_datablock /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/lib_id_delete.cc:77
    #13 0x46a3088 in blender::deg::deg_free_copy_on_write_datablock(ID*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:1017
    #14 0x46a26fd in blender::deg::deg_update_copy_on_write_datablock(blender::deg::Depsgraph const*, blender::deg::IDNode const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:896
    #15 0x46a35e3 in blender::deg::deg_evaluate_copy_on_write(Depsgraph*, blender::deg::IDNode const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:1032
    #16 0x4729aa1 in operator() /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc:182
    #17 0x4781e16 in __invoke_impl<void, blender::deg::DepsgraphNodeBuilder::add_id_node(ID*)::<lambda(Depsgraph*)>&, Depsgraph*> /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/invoke.h:61
    #18 0x4777ccc in __invoke_r<void, blender::deg::DepsgraphNodeBuilder::add_id_node(ID*)::<lambda(Depsgraph*)>&, Depsgraph*> /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/invoke.h:111
    #19 0x477177f in _M_invoke /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/std_function.h:290
    #20 0x469a772 in std::function<void (Depsgraph*)>::operator()(Depsgraph*) const /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/std_function.h:591
    #21 0x4694a81 in evaluate_node /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval.cc:102
    #22 0x4694ec2 in deg_task_run_func /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval.cc:119
    #23 0x45170de in Task::operator()() const /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenlib/intern/task_pool.cc:166
    #24 0x451c02e in tbb::internal::function_task<Task>::execute() /home/abdelrahman/Sources/programming/blender/lib/linux_x86_64/tbb/include/tbb/task.h:1059
    #25 0x7fa55a59f5b4 in tbb::internal::custom_scheduler<tbb::internal::IntelSchedulerTraits>::process_bypass_loop(tbb::internal::context_guard_helper<false>&, tbb::task*, long) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x2a5b4) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb)

previously allocated by thread T0 here:
    #0 0x7fa559ee1359 in __interceptor_malloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x47e96c4 in MEM_lockfree_mallocN /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/intern/mallocn_lockfree_impl.c:258
    #2 0x4a9dc3c in read_struct /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenloader/intern/readfile.cc:1811
    #3 0x4aa4936 in read_data_into_datamap /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenloader/intern/readfile.cc:2550
    #4 0x4aab6cc in read_libblock /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenloader/intern/readfile.cc:3025
    #5 0x4ab5192 in blo_read_file_internal(FileData*, char const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenloader/intern/readfile.cc:3668
    #6 0x4a88cdb in BLO_read_from_file /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenloader/intern/readblenentry.cc:417
    #7 0x8331f8 in BKE_blendfile_read(char const*, BlendFileReadParams const*, BlendFileReadReport*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/blendfile.cc:1030
    #8 0x48776bd in WM_file_read(bContext*, char const*, ReportList*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:1024
    #9 0x48846f9 in wm_file_read_opwrap /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2744
    #10 0x48857bb in wm_open_mainfile__open /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2870
    #11 0x4884a91 in operator_state_dispatch /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2780
    #12 0x4885995 in wm_open_mainfile_dispatch /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2891
    #13 0x4884d51 in wm_open_mainfile__discard_changes /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2819
    #14 0x4884a91 in operator_state_dispatch /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2780
    #15 0x4885995 in wm_open_mainfile_dispatch /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2891
    #16 0x48859be in wm_open_mainfile_invoke /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2896
    #17 0x482b5a6 in wm_operator_invoke /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:1550
    #18 0x482d47e in wm_operator_call_internal /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:1785
    #19 0x482d587 in WM_operator_name_call_ptr(bContext*, wmOperatorType*, wmOperatorCallContext, PointerRNA*, wmEvent const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:1799
    #20 0x482eb28 in WM_operator_name_call_ptr_with_depends_on_cursor(bContext*, wmOperatorType*, wmOperatorCallContext, PointerRNA*, wmEvent const*, char const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:1988
    #21 0x807c3d6 in ui_apply_but_funcs_after /home/abdelrahman/Sources/programming/blender/blender/source/blender/editors/interface/interface_handlers.cc:1039
    #22 0x81138b0 in ui_popup_handler /home/abdelrahman/Sources/programming/blender/blender/source/blender/editors/interface/interface_handlers.cc:11747
    #23 0x4824085 in wm_handler_ui_call /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:831
    #24 0x48447a9 in wm_handlers_do_intern /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:3333
    #25 0x4845bb1 in wm_handlers_do /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:3450
    #26 0x48501ce in wm_event_do_handlers(bContext*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:4077
    #27 0x47fbb3a in WM_main(bContext*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm.cc:613
    #28 0x80e26b in main /home/abdelrahman/Sources/programming/blender/blender/source/creator/creator.cc:575
    #29 0x7fa54f845ccf  (/usr/lib/libc.so.6+0x27ccf) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)

Thread T18 created by T0 here:
    #0 0x7fa559e4a497 in __interceptor_pthread_create /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_interceptors.cpp:208
    #1 0x7fa55a599be5 in tbb::internal::rml::private_server::wake_some(int) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x24be5) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb)

SUMMARY: AddressSanitizer: heap-use-after-free /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/intern/mallocn_lockfree_impl.c:98 in MEM_lockfree_freeN
Shadow bytes around the buggy address:
  0x60c000027980: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
  0x60c000027a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x60c000027a80: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x60c000027b00: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
  0x60c000027b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x60c000027c00: fa fa fa fa fa fa fa fa[fd]fd fd fd fd fd fd fd
  0x60c000027c80: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa
  0x60c000027d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x60c000027d80: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x60c000027e00: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa
  0x60c000027e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==1796374==ABORTING
When I try to use this `grease_pencil.remove_frames(*layer, frames_to_delete);` I get a crash. I ran Blender in a debugger to see if I can find what is causing the crash, but I haven't figured out the reason. I am sure I am missing something with this being my first time working with Blender's code. This is the output I get in the terminal after running the test file I am using. I can't see what might be causing the problem so I thought I would share it here in case someone can figure it out. ``` Traceback (most recent call last): File "/home/abdelrahman/.config/blender/4.1/scripts/addons/bone_layer_manager/constraint_operators.py", line 472, in poll idx = cbone.constraint_active_index ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'constraint_active_index' Traceback (most recent call last): File "/home/abdelrahman/.config/blender/4.1/scripts/addons/bone_layer_manager/constraint_operators.py", line 370, in poll return len(bone.constraints) > 0 and len(context.selected_pose_bones) > 1 ^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'constraints' Traceback (most recent call last): File "/home/abdelrahman/.config/blender/4.1/scripts/addons/bone_layer_manager/constraint_operators.py", line 404, in poll return len(bone.constraints) > 0 and len(context.selected_pose_bones) > 1 ^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'constraints' Traceback (most recent call last): File "/home/abdelrahman/.config/blender/4.1/scripts/addons/bone_layer_manager/constraint_operators.py", line 443, in poll return len(bone.constraints) > 0 and len(context.selected_pose_bones) > 1 ^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'constraints' Traceback (most recent call last): File "/home/abdelrahman/.config/blender/4.1/scripts/addons/bone_layer_manager/constraint_operators.py", line 260, in poll return len(bone.constraints) > 0 and len(context.selected_pose_bones) > 0 ^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'constraints' ================================================================= ==1796374==ERROR: AddressSanitizer: heap-use-after-free on address 0x60c000027c40 at pc 0x0000047e8a4d bp 0x7fa4ffff03d0 sp 0x7fa4ffff03c0 READ of size 8 at 0x60c000027c40 thread T18 #0 0x47e8a4c in MEM_lockfree_freeN /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/intern/mallocn_lockfree_impl.c:98 #1 0x374bfe9 in free_layer_data /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2150 #2 0x377b79e in CustomDataLayerImplicitSharing::delete_self_with_data() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2312 #3 0xa5ff14 in blender::ImplicitSharingInfo::remove_user_and_delete_if_last() const /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenlib/BLI_implicit_sharing.hh:145 #4 0x3750959 in customData_free_layer__internal /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2478 #5 0x3750cc3 in CustomData_free(CustomData*, int) /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2500 #6 0x35f7df0 in blender::bke::CurvesGeometry::~CurvesGeometry() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/curves_geometry.cc:174 #7 0xac1657 in blender::bke::greasepencil::Drawing::~Drawing() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:300 #8 0xb02cb8 in void MEM_delete<blender::bke::greasepencil::Drawing>(blender::bke::greasepencil::Drawing const*) /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/MEM_guardedalloc.h:292 #9 0xae30f9 in free_drawing_array /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:2359 #10 0xabf9f7 in grease_pencil_free_data /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:132 #11 0xdbf343 in BKE_libblock_free_datablock /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/lib_id_delete.cc:77 #12 0x46a3088 in blender::deg::deg_free_copy_on_write_datablock(ID*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:1017 #13 0x46a26fd in blender::deg::deg_update_copy_on_write_datablock(blender::deg::Depsgraph const*, blender::deg::IDNode const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:896 #14 0x46a35e3 in blender::deg::deg_evaluate_copy_on_write(Depsgraph*, blender::deg::IDNode const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:1032 #15 0x4729aa1 in operator() /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc:182 #16 0x4781e16 in __invoke_impl<void, blender::deg::DepsgraphNodeBuilder::add_id_node(ID*)::<lambda(Depsgraph*)>&, Depsgraph*> /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/invoke.h:61 #17 0x4777ccc in __invoke_r<void, blender::deg::DepsgraphNodeBuilder::add_id_node(ID*)::<lambda(Depsgraph*)>&, Depsgraph*> /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/invoke.h:111 #18 0x477177f in _M_invoke /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/std_function.h:290 #19 0x469a772 in std::function<void (Depsgraph*)>::operator()(Depsgraph*) const /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/std_function.h:591 #20 0x4694a81 in evaluate_node /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval.cc:102 #21 0x4694ec2 in deg_task_run_func /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval.cc:119 #22 0x45170de in Task::operator()() const /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenlib/intern/task_pool.cc:166 #23 0x451c02e in tbb::internal::function_task<Task>::execute() /home/abdelrahman/Sources/programming/blender/lib/linux_x86_64/tbb/include/tbb/task.h:1059 #24 0x7fa55a59f5b4 in tbb::internal::custom_scheduler<tbb::internal::IntelSchedulerTraits>::process_bypass_loop(tbb::internal::context_guard_helper<false>&, tbb::task*, long) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x2a5b4) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb) #25 0x7fa55a59f8f2 in tbb::internal::custom_scheduler<tbb::internal::IntelSchedulerTraits>::local_wait_for_all(tbb::task&, tbb::task*) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x2a8f2) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb) #26 0x7fa55a587776 in tbb::internal::arena::process(tbb::internal::generic_scheduler&) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x12776) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb) #27 0x7fa55a595f9f in tbb::internal::market::process(rml::job&) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x20f9f) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb) #28 0x7fa55a599d0d in tbb::internal::rml::private_worker::run() (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x24d0d) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb) #29 0x7fa55a599f88 in tbb::internal::rml::private_worker::thread_routine(void*) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x24f88) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb) #30 0x7fa54f8aa9ea (/usr/lib/libc.so.6+0x8c9ea) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658) #31 0x7fa54f92e7cb (/usr/lib/libc.so.6+0x1107cb) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658) 0x60c000027c40 is located 0 bytes inside of 128-byte region [0x60c000027c40,0x60c000027cc0) freed by thread T18 here: #0 0x7fa559edfdb2 in __interceptor_free /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:52 #1 0x47e8ce9 in MEM_lockfree_freeN /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/intern/mallocn_lockfree_impl.c:110 #2 0x374bfe9 in free_layer_data /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2150 #3 0x377b79e in CustomDataLayerImplicitSharing::delete_self_with_data() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2312 #4 0xa5ff14 in blender::ImplicitSharingInfo::remove_user_and_delete_if_last() const /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenlib/BLI_implicit_sharing.hh:145 #5 0x3750959 in customData_free_layer__internal /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2478 #6 0x3750cc3 in CustomData_free(CustomData*, int) /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/customdata.cc:2500 #7 0x35f7df0 in blender::bke::CurvesGeometry::~CurvesGeometry() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/curves_geometry.cc:174 #8 0xac1657 in blender::bke::greasepencil::Drawing::~Drawing() /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:300 #9 0xb02cb8 in void MEM_delete<blender::bke::greasepencil::Drawing>(blender::bke::greasepencil::Drawing const*) /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/MEM_guardedalloc.h:292 #10 0xae30f9 in free_drawing_array /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:2359 #11 0xabf9f7 in grease_pencil_free_data /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/grease_pencil.cc:132 #12 0xdbf343 in BKE_libblock_free_datablock /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/lib_id_delete.cc:77 #13 0x46a3088 in blender::deg::deg_free_copy_on_write_datablock(ID*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:1017 #14 0x46a26fd in blender::deg::deg_update_copy_on_write_datablock(blender::deg::Depsgraph const*, blender::deg::IDNode const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:896 #15 0x46a35e3 in blender::deg::deg_evaluate_copy_on_write(Depsgraph*, blender::deg::IDNode const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc:1032 #16 0x4729aa1 in operator() /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc:182 #17 0x4781e16 in __invoke_impl<void, blender::deg::DepsgraphNodeBuilder::add_id_node(ID*)::<lambda(Depsgraph*)>&, Depsgraph*> /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/invoke.h:61 #18 0x4777ccc in __invoke_r<void, blender::deg::DepsgraphNodeBuilder::add_id_node(ID*)::<lambda(Depsgraph*)>&, Depsgraph*> /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/invoke.h:111 #19 0x477177f in _M_invoke /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/std_function.h:290 #20 0x469a772 in std::function<void (Depsgraph*)>::operator()(Depsgraph*) const /usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/include/c++/bits/std_function.h:591 #21 0x4694a81 in evaluate_node /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval.cc:102 #22 0x4694ec2 in deg_task_run_func /home/abdelrahman/Sources/programming/blender/blender/source/blender/depsgraph/intern/eval/deg_eval.cc:119 #23 0x45170de in Task::operator()() const /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenlib/intern/task_pool.cc:166 #24 0x451c02e in tbb::internal::function_task<Task>::execute() /home/abdelrahman/Sources/programming/blender/lib/linux_x86_64/tbb/include/tbb/task.h:1059 #25 0x7fa55a59f5b4 in tbb::internal::custom_scheduler<tbb::internal::IntelSchedulerTraits>::process_bypass_loop(tbb::internal::context_guard_helper<false>&, tbb::task*, long) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x2a5b4) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb) previously allocated by thread T0 here: #0 0x7fa559ee1359 in __interceptor_malloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:69 #1 0x47e96c4 in MEM_lockfree_mallocN /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/intern/mallocn_lockfree_impl.c:258 #2 0x4a9dc3c in read_struct /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenloader/intern/readfile.cc:1811 #3 0x4aa4936 in read_data_into_datamap /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenloader/intern/readfile.cc:2550 #4 0x4aab6cc in read_libblock /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenloader/intern/readfile.cc:3025 #5 0x4ab5192 in blo_read_file_internal(FileData*, char const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenloader/intern/readfile.cc:3668 #6 0x4a88cdb in BLO_read_from_file /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenloader/intern/readblenentry.cc:417 #7 0x8331f8 in BKE_blendfile_read(char const*, BlendFileReadParams const*, BlendFileReadReport*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/blenkernel/intern/blendfile.cc:1030 #8 0x48776bd in WM_file_read(bContext*, char const*, ReportList*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:1024 #9 0x48846f9 in wm_file_read_opwrap /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2744 #10 0x48857bb in wm_open_mainfile__open /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2870 #11 0x4884a91 in operator_state_dispatch /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2780 #12 0x4885995 in wm_open_mainfile_dispatch /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2891 #13 0x4884d51 in wm_open_mainfile__discard_changes /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2819 #14 0x4884a91 in operator_state_dispatch /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2780 #15 0x4885995 in wm_open_mainfile_dispatch /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2891 #16 0x48859be in wm_open_mainfile_invoke /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_files.cc:2896 #17 0x482b5a6 in wm_operator_invoke /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:1550 #18 0x482d47e in wm_operator_call_internal /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:1785 #19 0x482d587 in WM_operator_name_call_ptr(bContext*, wmOperatorType*, wmOperatorCallContext, PointerRNA*, wmEvent const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:1799 #20 0x482eb28 in WM_operator_name_call_ptr_with_depends_on_cursor(bContext*, wmOperatorType*, wmOperatorCallContext, PointerRNA*, wmEvent const*, char const*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:1988 #21 0x807c3d6 in ui_apply_but_funcs_after /home/abdelrahman/Sources/programming/blender/blender/source/blender/editors/interface/interface_handlers.cc:1039 #22 0x81138b0 in ui_popup_handler /home/abdelrahman/Sources/programming/blender/blender/source/blender/editors/interface/interface_handlers.cc:11747 #23 0x4824085 in wm_handler_ui_call /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:831 #24 0x48447a9 in wm_handlers_do_intern /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:3333 #25 0x4845bb1 in wm_handlers_do /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:3450 #26 0x48501ce in wm_event_do_handlers(bContext*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm_event_system.cc:4077 #27 0x47fbb3a in WM_main(bContext*) /home/abdelrahman/Sources/programming/blender/blender/source/blender/windowmanager/intern/wm.cc:613 #28 0x80e26b in main /home/abdelrahman/Sources/programming/blender/blender/source/creator/creator.cc:575 #29 0x7fa54f845ccf (/usr/lib/libc.so.6+0x27ccf) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658) Thread T18 created by T0 here: #0 0x7fa559e4a497 in __interceptor_pthread_create /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_interceptors.cpp:208 #1 0x7fa55a599be5 in tbb::internal::rml::private_server::wake_some(int) (/home/abdelrahman/Sources/programming/blender/build_linux_debug/bin/lib/libtbb.so.2+0x24be5) (BuildId: efcc170f66e9a8108477d04e9164946672875ebb) SUMMARY: AddressSanitizer: heap-use-after-free /home/abdelrahman/Sources/programming/blender/blender/intern/guardedalloc/intern/mallocn_lockfree_impl.c:98 in MEM_lockfree_freeN Shadow bytes around the buggy address: 0x60c000027980: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa 0x60c000027a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x60c000027a80: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00 0x60c000027b00: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa 0x60c000027b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x60c000027c00: fa fa fa fa fa fa fa fa[fd]fd fd fd fd fd fd fd 0x60c000027c80: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa 0x60c000027d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x60c000027d80: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd 0x60c000027e00: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa 0x60c000027e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==1796374==ABORTING ```
const FramesMapKey next = keys[i + 1];
amsaid1989 marked this conversation as resolved Outdated

Can be const?

Can be const?

Changed to const

Changed to `const`
GreasePencilFrame frame = layer->frames().lookup(current);
if (selected && !frame.is_selected()) {
continue;
}
Drawing *drawing = grease_pencil.get_editable_drawing_at(*layer, current);
Drawing *drawing_next = grease_pencil.get_editable_drawing_at(*layer, next);
if (!drawing || !drawing_next) {
continue;
}
bke::CurvesGeometry &curves = drawing->strokes_for_write();
bke::CurvesGeometry &curves_next = drawing_next->strokes_for_write();
if (!curves_geometry_is_equal(curves, curves_next)) {
continue;
}
frames_to_delete.append(next);
}
for (const FramesMapKey frame : frames_to_delete) {
layer->remove_frame(frame);
}
changed = true;
}
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr);
}
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_insert_blank_frame(wmOperatorType *ot)
{
PropertyRNA *prop;
@ -432,6 +587,27 @@ static void GREASE_PENCIL_OT_insert_blank_frame(wmOperatorType *ot)
RNA_def_int(ot->srna, "duration", 0, 0, MAXFRAME, "Duration", "", 0, 100);
}
static void GREASE_PENCIL_OT_frame_clean_duplicate(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Delete Duplicate Frames";
ot->idname = "GREASE_PENCIL_OT_frame_clean_duplicate";
ot->description = "Remove any keyframe that is a duplicate of the previous one";
/* callbacks */
ot->exec = frame_clean_duplicate_exec;
ot->poll = active_grease_pencil_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
prop = RNA_def_boolean(
ot->srna, "selected", false, "Selected", "Only delete selected keyframes");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
bool grease_pencil_copy_keyframes(bAnimContext *ac, KeyframeClipboard &clipboard)
{
using namespace bke::greasepencil;
@ -632,4 +808,5 @@ void ED_operatortypes_grease_pencil_frames()
{
using namespace blender::ed::greasepencil;
WM_operatortype_append(GREASE_PENCIL_OT_insert_blank_frame);
WM_operatortype_append(GREASE_PENCIL_OT_frame_clean_duplicate);
}