summaryrefslogtreecommitdiff
path: root/clutter/clutter-state.c
diff options
context:
space:
mode:
authorØyvind Kolås <pippin@linux.intel.com>2010-08-17 13:22:08 +0100
committerØyvind Kolås <pippin@linux.intel.com>2010-08-23 14:01:08 +0100
commit04d55107f380340ce22fbb56a3c87cf7576524db (patch)
treef7e19b25ea090676672ff99c919f422c8d890ebd /clutter/clutter-state.c
parent66018a7035ccdc2422f8eef9a9523339fd6309be (diff)
downloadclutter-04d55107f380340ce22fbb56a3c87cf7576524db.tar.gz
state: clutter_state_remove_key_internal fix memory corruption
When we free a state because there are no more keys with it as a target use a goto to re-initialize temporary variables that have become invalid. Fixing bug #2273
Diffstat (limited to 'clutter/clutter-state.c')
-rw-r--r--clutter/clutter-state.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/clutter/clutter-state.c b/clutter/clutter-state.c
index 12cde6fba..b05338af4 100644
--- a/clutter/clutter-state.c
+++ b/clutter/clutter-state.c
@@ -269,6 +269,8 @@ clutter_state_remove_key_internal (ClutterState *this,
if (source_state_name)
source_state = clutter_state_fetch_state (this, source_state_name, FALSE);
+again_from_start:
+
if (target_state_name != NULL)
state_list = g_list_append (NULL, (gpointer) target_state_name);
else
@@ -278,31 +280,36 @@ clutter_state_remove_key_internal (ClutterState *this,
{
State *target_state;
target_state = clutter_state_fetch_state (this, s->data, FALSE);
-
+ /* Go through each TargetState */
if (target_state)
{
GList *k;
-again:
+again_for_target_state:
for (k = target_state->keys; k != NULL; k = k->next)
{
ClutterStateKey *key = k->data;
+ /* Check if each key matches query */
if ( (object == NULL || (object == key->object))
&& (source_state == NULL || (source_state == key->source_state))
&& (property_name == NULL || ((property_name == key->property_name))))
{
+ /* Remove matching key */
target_state->keys = g_list_remove (target_state->keys, key);
+ key->is_inert = is_inert;
+ clutter_state_key_free (key);
+ /* no more keys with transitions to this target_state*/
if (target_state->keys == NULL)
{
- /* no more keys, so remove this state */
+ /* remove any keys that exist that uses this state as a source */
clutter_state_remove_key (this, s->data, NULL, NULL, NULL);
+
g_hash_table_remove (this->priv->states, s->data);
+ goto again_from_start; /* we have just freed State *target_state, so
+ need to restart removal */
}
-
- key->is_inert = is_inert;
- clutter_state_key_free (key);
- goto again;
+ goto again_for_target_state;
}
}
}