Ver Fonte

wayland: Avoid dereferencing a nil data offer

Pass the data device to the selection offer update functions instead of pulling it from the offer, as the offer may be nil.
Frank Praznik há 1 semana atrás
pai
commit
84cd92d705

+ 1 - 1
src/video/wayland/SDL_waylandclipboard.c

@@ -65,7 +65,7 @@ bool Wayland_SetClipboardData(SDL_VideoDevice *_this)
             SDL_WaylandDataSource *source = Wayland_DataSourceCreate(video_data);
             SDL_WaylandDataSource *source = Wayland_DataSourceCreate(video_data);
             Wayland_DataSourceSetCallback(source, _this->clipboard_callback, _this->clipboard_userdata, _this->clipboard_sequence);
             Wayland_DataSourceSetCallback(source, _this->clipboard_callback, _this->clipboard_userdata, _this->clipboard_sequence);
 
 
-            result = Wayland_DataDeviceSetSelection(data_device, source, (const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types);
+            result = Wayland_DataDeviceSetSelectionSource(data_device, source, (const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types);
             if (!result) {
             if (!result) {
                 Wayland_DataSourceDestroy(source);
                 Wayland_DataSourceDestroy(source);
             }
             }

+ 27 - 12
src/video/wayland/SDL_waylanddatamanager.c

@@ -463,6 +463,8 @@ void Wayland_PrimarySelectionSourceDestroy(SDL_WaylandPrimarySelectionSource *so
     }
     }
 }
 }
 
 
+static void SelectionOfferNotifyFromMIMEs(SDL_WaylandDataDevice *data_device, bool check_origin);
+
 static void offer_source_done_handler(void *data, struct wl_callback *callback, uint32_t callback_data)
 static void offer_source_done_handler(void *data, struct wl_callback *callback, uint32_t callback_data)
 {
 {
     if (!callback) {
     if (!callback) {
@@ -485,7 +487,7 @@ static void offer_source_done_handler(void *data, struct wl_callback *callback,
         const bool source_is_external = SDL_strncmp(offer->data_device->id_str, id, length) != 0;
         const bool source_is_external = SDL_strncmp(offer->data_device->id_str, id, length) != 0;
         SDL_free(id);
         SDL_free(id);
         if (source_is_external) {
         if (source_is_external) {
-            Wayland_DataOfferNotifyFromMIMEs(offer, false);
+            SelectionOfferNotifyFromMIMEs(offer->data_device, false);
         } else {
         } else {
             // Recursive data offer; just destroy it.
             // Recursive data offer; just destroy it.
             SDL_WaylandDataDevice *data_device = offer->data_device;
             SDL_WaylandDataDevice *data_device = offer->data_device;
@@ -528,9 +530,9 @@ static void DataOfferCheckSource(SDL_WaylandDataOffer *offer, const char *mime_t
     }
     }
 }
 }
 
 
-static void SetCurrentClipboardOffer(SDL_WaylandDataOffer *offer)
+static void UpdateSeatOffers(SDL_WaylandDataDevice *data_device)
 {
 {
-    SDL_WaylandSeat *offer_seat = offer->data_device->seat;
+    SDL_WaylandSeat *offer_seat = data_device->seat;
     SDL_VideoData *video_data = offer_seat->display;
     SDL_VideoData *video_data = offer_seat->display;
 
 
     // Clear any existing references to the existing clipboard data before replacing the current offer.
     // Clear any existing references to the existing clipboard data before replacing the current offer.
@@ -551,10 +553,12 @@ static void SetCurrentClipboardOffer(SDL_WaylandDataOffer *offer)
     video_data->current_data_offer_seat = offer_seat;
     video_data->current_data_offer_seat = offer_seat;
 }
 }
 
 
-void Wayland_DataOfferNotifyFromMIMEs(SDL_WaylandDataOffer *offer, bool check_origin)
+static void SelectionOfferNotifyFromMIMEs(SDL_WaylandDataDevice *data_device, bool check_origin)
 {
 {
-    int nformats = 0;
+    SDL_WaylandDataOffer *offer = data_device->selection_offer;
     char **new_mime_types = NULL;
     char **new_mime_types = NULL;
+    size_t num_formats = 0;
+
     if (offer) {
     if (offer) {
         size_t alloc_size = 0;
         size_t alloc_size = 0;
 
 
@@ -571,11 +575,11 @@ void Wayland_DataOfferNotifyFromMIMEs(SDL_WaylandDataOffer *offer, bool check_or
                 return;
                 return;
             }
             }
 
 
-            ++nformats;
+            ++num_formats;
             alloc_size += SDL_strlen(item->mime_type) + 1;
             alloc_size += SDL_strlen(item->mime_type) + 1;
         }
         }
 
 
-        alloc_size += (nformats + 1) * sizeof(char *);
+        alloc_size += (num_formats + 1) * sizeof(char *);
 
 
         new_mime_types = SDL_AllocateTemporaryMemory(alloc_size);
         new_mime_types = SDL_AllocateTemporaryMemory(alloc_size);
         if (!new_mime_types) {
         if (!new_mime_types) {
@@ -584,7 +588,7 @@ void Wayland_DataOfferNotifyFromMIMEs(SDL_WaylandDataOffer *offer, bool check_or
         }
         }
 
 
         // Second pass to fill.
         // Second pass to fill.
-        char *strPtr = (char *)(new_mime_types + nformats + 1);
+        char *strPtr = (char *)(new_mime_types + num_formats + 1);
         item = NULL;
         item = NULL;
         int i = 0;
         int i = 0;
         wl_list_for_each(item, &offer->mimes, link) {
         wl_list_for_each(item, &offer->mimes, link) {
@@ -596,11 +600,22 @@ void Wayland_DataOfferNotifyFromMIMEs(SDL_WaylandDataOffer *offer, bool check_or
             strPtr = stpcpy(strPtr, item->mime_type) + 1;
             strPtr = stpcpy(strPtr, item->mime_type) + 1;
             i++;
             i++;
         }
         }
-        new_mime_types[nformats] = NULL;
+        new_mime_types[num_formats] = NULL;
     }
     }
 
 
-    SetCurrentClipboardOffer(offer);
-    SDL_SendClipboardUpdate(false, new_mime_types, nformats);
+    UpdateSeatOffers(data_device);
+    SDL_SendClipboardUpdate(false, new_mime_types, num_formats);
+}
+
+void Wayland_DataDeviceSetSelectionOffer(SDL_WaylandDataDevice *data_device, SDL_WaylandDataOffer *offer)
+{
+    // Don't notify when clearing the old selection offer if doing so will inadvertently clear the selection source.
+    const bool notify = offer || (!offer && data_device->selection_offer && (!data_device->selection_offer->callback || !data_device->selection_source));
+    Wayland_DataOfferDestroy(data_device->selection_offer);
+    data_device->selection_offer = offer;
+    if (notify) {
+        SelectionOfferNotifyFromMIMEs(data_device, true);
+    }
 }
 }
 
 
 void *Wayland_DataOfferReceive(SDL_WaylandDataOffer *offer, const char *mime_type, size_t *length, bool extended_timeout)
 void *Wayland_DataOfferReceive(SDL_WaylandDataOffer *offer, const char *mime_type, size_t *length, bool extended_timeout)
@@ -726,7 +741,7 @@ void Wayland_PrimarySelectionOfferDestroy(SDL_WaylandPrimarySelectionOffer *offe
     }
     }
 }
 }
 
 
-bool Wayland_DataDeviceSetSelection(SDL_WaylandDataDevice *data_device, SDL_WaylandDataSource *source, const char **mime_types, size_t mime_count)
+bool Wayland_DataDeviceSetSelectionSource(SDL_WaylandDataDevice *data_device, SDL_WaylandDataSource *source, const char **mime_types, size_t mime_count)
 {
 {
     if (!data_device) {
     if (!data_device) {
         return SDL_SetError("Invalid Data Device");
         return SDL_SetError("Invalid Data Device");

+ 2 - 2
src/video/wayland/SDL_waylanddatamanager.h

@@ -130,7 +130,7 @@ extern void Wayland_PrimarySelectionSourceDestroy(SDL_WaylandPrimarySelectionSou
 extern void *Wayland_DataOfferReceive(SDL_WaylandDataOffer *offer, const char *mime_type, size_t *length, bool extended_timeout);
 extern void *Wayland_DataOfferReceive(SDL_WaylandDataOffer *offer, const char *mime_type, size_t *length, bool extended_timeout);
 extern void *Wayland_PrimarySelectionOfferReceive(SDL_WaylandPrimarySelectionOffer *offer, const char *mime_type, size_t *length);
 extern void *Wayland_PrimarySelectionOfferReceive(SDL_WaylandPrimarySelectionOffer *offer, const char *mime_type, size_t *length);
 extern bool Wayland_DataOfferHasMIME(SDL_WaylandDataOffer *offer, const char *mime_type);
 extern bool Wayland_DataOfferHasMIME(SDL_WaylandDataOffer *offer, const char *mime_type);
-extern void Wayland_DataOfferNotifyFromMIMEs(SDL_WaylandDataOffer *offer, bool check_origin);
+extern void Wayland_DataDeviceSetSelectionOffer(SDL_WaylandDataDevice *data_device, SDL_WaylandDataOffer *offer);
 extern bool Wayland_PrimarySelectionOfferHasMIME(SDL_WaylandPrimarySelectionOffer *offer, const char *mime_type);
 extern bool Wayland_PrimarySelectionOfferHasMIME(SDL_WaylandPrimarySelectionOffer *offer, const char *mime_type);
 extern bool Wayland_DataOfferAddMIME(SDL_WaylandDataOffer *offer, const char *mime_type);
 extern bool Wayland_DataOfferAddMIME(SDL_WaylandDataOffer *offer, const char *mime_type);
 extern bool Wayland_PrimarySelectionOfferAddMIME(SDL_WaylandPrimarySelectionOffer *offer, const char *mime_type);
 extern bool Wayland_PrimarySelectionOfferAddMIME(SDL_WaylandPrimarySelectionOffer *offer, const char *mime_type);
@@ -138,7 +138,7 @@ extern void Wayland_DataOfferDestroy(SDL_WaylandDataOffer *offer);
 extern void Wayland_PrimarySelectionOfferDestroy(SDL_WaylandPrimarySelectionOffer *offer);
 extern void Wayland_PrimarySelectionOfferDestroy(SDL_WaylandPrimarySelectionOffer *offer);
 
 
 // Clipboard / Primary Selection
 // Clipboard / Primary Selection
-extern bool Wayland_DataDeviceSetSelection(SDL_WaylandDataDevice *device, SDL_WaylandDataSource *source, const char **mime_types, size_t mime_count);
+extern bool Wayland_DataDeviceSetSelectionSource(SDL_WaylandDataDevice *device, SDL_WaylandDataSource *source, const char **mime_types, size_t mime_count);
 extern bool Wayland_PrimarySelectionDeviceSetSelection(SDL_WaylandPrimarySelectionDevice *device, SDL_WaylandPrimarySelectionSource *source, const char *const *mime_types, size_t mime_count);
 extern bool Wayland_PrimarySelectionDeviceSetSelection(SDL_WaylandPrimarySelectionDevice *device, SDL_WaylandPrimarySelectionSource *source, const char *const *mime_types, size_t mime_count);
 extern void Wayland_DataDeviceSetSerial(SDL_WaylandDataDevice *device, uint32_t serial);
 extern void Wayland_DataDeviceSetSerial(SDL_WaylandDataDevice *device, uint32_t serial);
 extern void Wayland_PrimarySelectionDeviceSetSerial(SDL_WaylandPrimarySelectionDevice *device, uint32_t serial);
 extern void Wayland_PrimarySelectionDeviceSetSerial(SDL_WaylandPrimarySelectionDevice *device, uint32_t serial);

+ 1 - 7
src/video/wayland/SDL_waylandevents.c

@@ -2943,13 +2943,7 @@ static void data_device_handle_selection(void *data, struct wl_data_device *wl_d
                  ". In data_device_listener . data_device_handle_selection on data_offer 0x%08x",
                  ". In data_device_listener . data_device_handle_selection on data_offer 0x%08x",
                  (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1));
                  (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1));
 
 
-    // Don't notify when clearing the old selection offer if doing so will inadvertently clear the selection source.
-    const bool notify = offer || (!offer && data_device->selection_offer && (!data_device->selection_offer->callback || !data_device->selection_source));
-    Wayland_DataOfferDestroy(data_device->selection_offer);
-    data_device->selection_offer = offer;
-    if (notify) {
-        Wayland_DataOfferNotifyFromMIMEs(offer, true);
-    }
+    Wayland_DataDeviceSetSelectionOffer(data_device, offer);
 }
 }
 
 
 static const struct wl_data_device_listener data_device_listener = {
 static const struct wl_data_device_listener data_device_listener = {