Depsgraph: Fix particle system freeing accessing freed particle settings

Need to ensure CoW IDs are freed in the right order.
This commit is contained in:
Sergey Sharybin 2017-07-19 15:50:49 +02:00
parent 496d18614f
commit 53c1d15675
5 changed files with 47 additions and 0 deletions

View File

@ -53,6 +53,8 @@ extern "C" {
#include "DEG_depsgraph.h"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
@ -250,11 +252,13 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
/* Node Management ---------------------------- */
#ifndef WITH_COPY_ON_WRITE
static void id_node_deleter(void *value)
{
IDDepsNode *id_node = reinterpret_cast<IDDepsNode *>(value);
OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
}
#endif
TimeSourceDepsNode *Depsgraph::add_time_source()
{
@ -299,7 +303,27 @@ IDDepsNode *Depsgraph::add_id_node(ID *id, const char *name, bool do_tag)
void Depsgraph::clear_id_nodes()
{
#ifndef WITH_COPY_ON_WRITE
BLI_ghash_clear(id_hash, NULL, id_node_deleter);
#else
/* Stupid workaround to ensure we free IDs in a proper order. */
GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, id_hash)
{
if (!deg_copy_on_write_is_expanded(id_node->id_cow)) {
continue;
}
const short id_type = GS(id_node->id_cow->name);
if (id_type != ID_PA) {
id_node->destroy();
}
}
GHASH_FOREACH_END();
GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, id_hash)
{
OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
}
GHASH_FOREACH_END();
#endif
}
/* Add new relationship between two nodes. */

View File

@ -742,4 +742,9 @@ void deg_tag_copy_on_write_id(ID *id_cow, const ID *id_orig)
id_cow->newid = (ID *)id_orig;
}
bool deg_copy_on_write_is_expanded(const struct ID *id_cow)
{
return check_datablock_expanded(id_cow);
}
} // namespace DEG

View File

@ -86,4 +86,10 @@ bool deg_validate_copy_on_write_datablock(ID *id_cow);
/* Tag given ID block as being copy-on-wtritten. */
void deg_tag_copy_on_write_id(struct ID *id_cow, const struct ID *id_orig);
/* Check whether ID datablock is expanded.
*
* TODO(sergey): Make it an inline function or a macro.
*/
bool deg_copy_on_write_is_expanded(const struct ID *id_cow);
} // namespace DEG

View File

@ -191,6 +191,15 @@ void IDDepsNode::init(const ID *id, const char *UNUSED(subdata))
/* Free 'id' node. */
IDDepsNode::~IDDepsNode()
{
destroy();
}
void IDDepsNode::destroy()
{
if (id_orig == NULL) {
return;
}
BLI_ghash_free(components,
id_deps_node_hash_key_free,
id_deps_node_hash_value_free);
@ -202,6 +211,8 @@ IDDepsNode::~IDDepsNode()
DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n",
id_orig->name, id_orig, id_cow);
#endif
/* Tag that the node is freed. */
id_orig = NULL;
}
ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,

View File

@ -139,6 +139,7 @@ struct IDDepsNode : public DepsNode {
void init(const ID *id, const char *subdata);
~IDDepsNode();
void destroy();
ComponentDepsNode *find_component(eDepsNode_Type type,
const char *name = "") const;