diff options
author | Yonit Halperin <yhalperi@redhat.com> | 2011-07-12 08:50:34 +0300 |
---|---|---|
committer | Yonit Halperin <yhalperi@redhat.com> | 2011-07-12 09:01:26 +0300 |
commit | 686b67473f30043033deeaf0f1eb644915d792cd (patch) | |
tree | 083dbbb642a22d4d491a28e6e34d7b5fe4831270 | |
parent | 7e83957d2244be5469702260b3afe147d3784754 (diff) |
server: fix access to a released drawable. RHBZ #713474
red_pipe_add_drawable can lead to removal of drawables from current tree
(since it calls red_handle_drawable_surfaces_client_synced), which can
also lead to releasing these drawables.
Before the fix, red_current_add_equal, called red_pipe_add_drawable,
without assuring afterwards that the drawables it refers to are still alive or
still in the current tree.
-rw-r--r-- | server/red_worker.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/server/red_worker.c b/server/red_worker.c index 9a61e86d..672f0781 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -2703,22 +2703,29 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI int add_after = !!other_drawable->stream && is_drawable_independent_from_surfaces(drawable); red_stream_maintenance(worker, drawable, other_drawable); __current_add_drawable(worker, drawable, &other->siblings_link); + other_drawable->refs++; + current_remove_drawable(worker, other_drawable); if (add_after) { red_pipe_add_drawable_after(worker, drawable, other_drawable); } else { red_pipe_add_drawable(worker, drawable); } - remove_drawable(worker, other_drawable); + red_pipe_remove_drawable(worker, other_drawable); + release_drawable(worker, other_drawable); return TRUE; } switch (item->effect) { case QXL_EFFECT_REVERT_ON_DUP: if (is_same_drawable(worker, drawable, other_drawable)) { + other_drawable->refs++; + current_remove_drawable(worker, other_drawable); if (!ring_item_is_linked(&other_drawable->pipe_item.link)) { red_pipe_add_drawable(worker, drawable); + } else { + red_pipe_remove_drawable(worker, other_drawable); } - remove_drawable(worker, other_drawable); + release_drawable(worker, other_drawable); return TRUE; } break; |