selection: dnd: fix wl_data_offer_destroy() race

At the end of a drag-and-drop operation, we need to call
`wl_data_offer_finish()`.

We *must* ensure the data offer hasn’t been destroyed before
that. This could previously happen if the compositor decided to send a
regular clipboard offer *after* we had started a drop operation,
but *before* it had finished. The dnd offer was then destroyed when
the clipboard offer was received, causing us to crash in
`wl_data_offer_finish()`.

To handle this, let the receive_offer_context take over ownership of
the data_offer pointer, and “manually” destroy it *after* calling
`wl_data_offer_finish()` in `receive_dnd_done()`.

Note: we should not, and can not, do the same thing for regular
clipboard and primary selection offers; such offers can be used
multiple times and should *not* be destroyed after a single copy
operation.
This commit is contained in:
Daniel Eklöf 2020-10-31 10:36:11 +01:00
parent dddeb14e1a
commit 102d4975a1
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

View file

@ -1777,6 +1777,7 @@ receive_dnd_done(void *user)
struct receive_offer_context *ctx = user;
wl_data_offer_finish(ctx->data_offer);
wl_data_offer_destroy(ctx->data_offer);
receive_offer_done(user);
}
@ -1827,6 +1828,10 @@ drop(void *data, struct wl_data_device *wl_data_device)
? &receive_offer_uri
: &receive_offer_text),
&receive_dnd_done, ctx);
/* data offer is now “owned” by the receive context */
clipboard->data_offer = NULL;
clipboard->mime_type = DATA_OFFER_MIME_UNSET;
}
static void