From 694158fc8ae9420b7d06e88fd030e3cfc8156841 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 02 2022 16:09:06 +0000 Subject: import fltk-1.3.4-3.el7_9 --- diff --git a/SOURCES/fltk-1.3.4-fix-segfault-if-using-very-large-selections.patch b/SOURCES/fltk-1.3.4-fix-segfault-if-using-very-large-selections.patch new file mode 100644 index 0000000..c05c2a5 --- /dev/null +++ b/SOURCES/fltk-1.3.4-fix-segfault-if-using-very-large-selections.patch @@ -0,0 +1,118 @@ +From 5e46e3380887dcd30dc7ea582496bbd9a6a4d70c Mon Sep 17 00:00:00 2001 +From: Albrecht Schlosser +Date: Fri, 1 Jul 2022 18:49:57 +0200 +Subject: [PATCH] Fix "Segfault if using very large selections" (issue 451) + +Backported from 'master' (fltk 1.4.0). For more information see + commit c5556291624eec58ed9de186474dfcc858dca691 and issue 451 + https://github.com/fltk/fltk/issues/451 +--- + src/Fl_x.cxx | 66 +++++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 50 insertions(+), 16 deletions(-) + +diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx +index 7c03d33..c8b9c06 100644 +--- a/src/Fl_x.cxx ++++ b/src/Fl_x.cxx +@@ -1273,19 +1273,24 @@ static bool getNextEvent(XEvent *event_return) + return true; + } + +-static long getIncrData(uchar* &data, const XSelectionEvent& selevent, long lower_bound) +-{ +-//fprintf(stderr,"Incremental transfer starting due to INCR property\n"); ++static long getIncrData(uchar* &data, const XSelectionEvent& selevent, size_t lower_bound) { ++ // fprintf(stderr,"Incremental transfer starting due to INCR property\n"); + size_t total = 0; + XEvent event; +- XDeleteProperty(fl_display, selevent.requestor, selevent.property); ++ XDeleteProperty(fl_display, selevent.requestor, selevent.property); + data = (uchar*)realloc(data, lower_bound); +- for (;;) +- { +- if (!getNextEvent(&event)) break; +- if (event.type == PropertyNotify) +- { +- if (event.xproperty.state != PropertyNewValue) continue; ++ if (!data) { ++ // fprintf(stderr, "[getIncrData:%d] realloc() FAILED, size = %ld\n", __LINE__, lower_bound); ++ Fl::fatal("Clipboard data transfer failed, size %ld too large.", lower_bound); ++ } ++ for (;;) { ++ if (!getNextEvent(&event)) { ++ // This is unexpected but may happen if the sender (clipboard owner) no longer sends data ++ // fprintf(stderr, "[getIncrData:%d] Failed to get next event (timeout) *** break! ***\n", __LINE__); ++ break; ++ } ++ if (event.type == PropertyNotify) { ++ if (event.xproperty.state != PropertyNewValue) continue; // ignore PropertyDelete + Atom actual_type; + int actual_format; + unsigned long nitems; +@@ -1300,15 +1305,39 @@ static long getIncrData(uchar* &data, const XSelectionEvent& selevent, long lowe + AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); + num_bytes = nitems * (actual_format / 8); + offset += num_bytes/4; +- //slice_size += num_bytes; +- if (total + num_bytes > (size_t)lower_bound) data = (uchar*)realloc(data, total + num_bytes); +- memcpy(data + total, prop, num_bytes); total += num_bytes; ++ // slice_size += num_bytes; ++ if (total + num_bytes > lower_bound) { ++ data = (uchar*)realloc(data, total + num_bytes); ++ if (!data) { ++ // fprintf(stderr, "[getIncrData():%d] realloc() FAILED, size = %ld\n", __LINE__, total + num_bytes); ++ Fl::fatal("Clipboard data transfer failed, size %ld too large.", total + num_bytes); ++ } ++ } ++ memcpy(data + total, prop, num_bytes); ++ total += num_bytes; + if (prop) XFree(prop); + } while (bytes_after != 0); + //fprintf(stderr,"INCR data size:%ld\n", slice_size); + if (num_bytes == 0) break; + } +- else break; ++ else { ++ // Unexpected next event. At this point we're handling the INCR protocol and can't deal with ++ // *some* other events due to potential recursions. We *could* call fl_handle(event) to handle ++ // *selected* other events but for the time being we ignore all other events! ++ // Handling the INCR protocol for very large data may take some time and multiple events. ++ // Interleaving "other" events are possible, for instance the KeyRelease event of the ++ // ctrl/v key pressed to insert the clipboard. This solution is not perfect but it can ++ // handle the INCR protocol with very large selections in most cases, although with potential ++ // side effects because other events may be ignored. ++ // See GitHub Issue #451: "Segfault if using very large selections". ++ // Note: the "fix" for Issue #451 is basically to use 'continue' rather than 'break' ++ // Debug: ++ // fprintf(stderr, ++ // "[getIncrData:%d] getNextEvent() returned %d, not PropertyNotify (%d). Event ignored.\n", ++ // __LINE__, event.type, PropertyNotify); ++ ++ continue; ++ } + } + XDeleteProperty(fl_display, selevent.requestor, selevent.property); + return (long)total; +@@ -1376,7 +1405,9 @@ int fl_handle(const XEvent& thisevent) + case SelectionNotify: { + static unsigned char* sn_buffer = 0; + //static const char *buffer_format = 0; +- if (sn_buffer) {XFree(sn_buffer); sn_buffer = 0;} ++ if (sn_buffer) { ++ free(sn_buffer); sn_buffer = 0; ++ } + long bytesread = 0; + if (fl_xevent->xselection.property) for (;;) { + // The Xdnd code pastes 64K chunks together, possibly to avoid +@@ -1457,7 +1488,10 @@ fprintf(stderr,"\n");*/ + return true; + } + if (actual == fl_INCR) { +- bytesread = getIncrData(sn_buffer, xevent.xselection, *(long*)portion); ++ // an X11 "integer" (32 bit), the "lower bound" of the clipboard size (see ICCCM) ++ size_t lower_bound = (*(unsigned long *)portion) & 0xFFFFFFFF; ++ // fprintf(stderr, "[fl_handle:%d] INCR: lower_bound = %ld\n", __LINE__, lower_bound); ++ bytesread = getIncrData(sn_buffer, xevent.xselection, lower_bound); + XFree(portion); + break; + } diff --git a/SOURCES/fltk-1.3.4-improve-x11-selection-data-transfer-protocol.patch b/SOURCES/fltk-1.3.4-improve-x11-selection-data-transfer-protocol.patch new file mode 100644 index 0000000..0c3da82 --- /dev/null +++ b/SOURCES/fltk-1.3.4-improve-x11-selection-data-transfer-protocol.patch @@ -0,0 +1,132 @@ +From 7ed06a7b65c6f91da50b6664c742208ce520a983 Mon Sep 17 00:00:00 2001 +From: Albrecht Schlosser +Date: Sat, 2 Jul 2022 16:08:20 +0200 +Subject: [PATCH] Improve X11 selection data transfer (INCR) protocol (issue + 451) + +This improves reading large selections and fixes one more bug. + +Backported from 'master' (fltk 1.4.0). For more information see + commit c5556291624eec58ed9de186474dfcc858dca691, + commit ef72df0dc7c3c48373c52085a855ac6ce6df4868 and issue 451 + https://github.com/fltk/fltk/issues/451 +--- + src/Fl_x.cxx | 64 ++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 49 insertions(+), 15 deletions(-) + +diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx +index c8b9c06..a3ec6f2 100644 +--- a/src/Fl_x.cxx ++++ b/src/Fl_x.cxx +@@ -1275,13 +1275,25 @@ static bool getNextEvent(XEvent *event_return) + + static long getIncrData(uchar* &data, const XSelectionEvent& selevent, size_t lower_bound) { + // fprintf(stderr,"Incremental transfer starting due to INCR property\n"); ++ // fprintf(stderr, "[getIncrData:%d] lower_bound [in ] =%10ld\n", __LINE__, lower_bound); ++ const size_t alloc_min = 4 * 1024 * 1024; // min. initial allocation ++ const size_t alloc_max = 200 * 1024 * 1024; // max. initial allocation ++ const size_t alloc_inc = 4 * 1024 * 1024; // (min.) increase if necessary + size_t total = 0; ++ size_t data_size = lower_bound + 1; ++ if (data_size < alloc_min) { ++ data_size = alloc_min; ++ } else if (data_size > alloc_max) { ++ data_size = alloc_max; ++ } ++ // fprintf(stderr, "[getIncrData:%d] initial alloc. =%10ld\n", __LINE__, data_size); ++ + XEvent event; + XDeleteProperty(fl_display, selevent.requestor, selevent.property); +- data = (uchar*)realloc(data, lower_bound); ++ data = (uchar*)realloc(data, data_size); + if (!data) { +- // fprintf(stderr, "[getIncrData:%d] realloc() FAILED, size = %ld\n", __LINE__, lower_bound); +- Fl::fatal("Clipboard data transfer failed, size %ld too large.", lower_bound); ++ // fprintf(stderr, "[getIncrData:%d] realloc() FAILED, size = %ld\n", __LINE__, data_size); ++ Fl::fatal("Clipboard data transfer failed, size %ld is too large.", data_size); + } + for (;;) { + if (!getNextEvent(&event)) { +@@ -1297,20 +1309,24 @@ static long getIncrData(uchar* &data, const XSelectionEvent& selevent, size_t lo + unsigned long bytes_after; + unsigned char* prop = 0; + long offset = 0; +- size_t num_bytes; ++ size_t num_bytes = 0; + //size_t slice_size = 0; +- do +- { ++ do { + XGetWindowProperty(fl_display, selevent.requestor, selevent.property, offset, 70000, True, + AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); + num_bytes = nitems * (actual_format / 8); + offset += num_bytes/4; + // slice_size += num_bytes; +- if (total + num_bytes > lower_bound) { +- data = (uchar*)realloc(data, total + num_bytes); ++ if (total + num_bytes + bytes_after + 1 > data_size) { ++ data_size += alloc_inc; ++ if (total + num_bytes + bytes_after + 1 > data_size) ++ data_size = total + num_bytes + bytes_after + 1; ++ // printf(" -- realloc(%9ld), total=%10ld, num_bytes=%7ld, bytes_after=%7ld (%7ld), required=%10ld\n", ++ // data_size, total, num_bytes, bytes_after, num_bytes + bytes_after, total + num_bytes + bytes_after + 1); ++ data = (uchar*)realloc(data, data_size); + if (!data) { +- // fprintf(stderr, "[getIncrData():%d] realloc() FAILED, size = %ld\n", __LINE__, total + num_bytes); +- Fl::fatal("Clipboard data transfer failed, size %ld too large.", total + num_bytes); ++ // fprintf(stderr, "[getIncrData():%d] realloc() FAILED, size = %ld\n", __LINE__, data_size); ++ Fl::fatal("Clipboard data transfer failed, size %ld is too large.", data_size); + } + } + memcpy(data + total, prop, num_bytes); +@@ -1340,6 +1356,7 @@ static long getIncrData(uchar* &data, const XSelectionEvent& selevent, size_t lo + } + } + XDeleteProperty(fl_display, selevent.requestor, selevent.property); ++ // fprintf(stderr, "[getIncrData:%d] total data [out] =%10ld\n", __LINE__, (long)total); + return (long)total; + } + +@@ -1488,20 +1505,37 @@ fprintf(stderr,"\n");*/ + return true; + } + if (actual == fl_INCR) { +- // an X11 "integer" (32 bit), the "lower bound" of the clipboard size (see ICCCM) +- size_t lower_bound = (*(unsigned long *)portion) & 0xFFFFFFFF; +- // fprintf(stderr, "[fl_handle:%d] INCR: lower_bound = %ld\n", __LINE__, lower_bound); ++ // From ICCCM: "The contents of the INCR property will be an integer, which ++ // represents a lower bound on the number of bytes of data in the selection." ++ // ++ // However, some X clients don't set the integer ("lower bound") in the INCR ++ // property, hence 'count' below is zero and we must not access '*portion'. ++ // Debug: ++#if (0) ++ fprintf(stderr, ++ "[fl_handle(SelectionNotify/INCR):%d] actual=%ld (INCR), format=%d, count=%ld, remaining=%ld", ++ __LINE__, actual, format, count, remaining); ++ if (portion && count > 0) { ++ fprintf(stderr, ++ ", portion=%p (%ld)", portion, *(long*)portion); ++ } ++ fprintf(stderr, "\n"); ++#endif ++ size_t lower_bound = 0; ++ if (portion && count > 0) { ++ lower_bound = *(unsigned long *)portion; ++ } + bytesread = getIncrData(sn_buffer, xevent.xselection, lower_bound); + XFree(portion); + break; + } + // Make sure we got something sane... + if ((portion == NULL) || (format != 8) || (count == 0)) { +- if (portion) { XFree(portion); portion = 0; } ++ if (portion) XFree(portion); + return true; + } + sn_buffer = (unsigned char*)realloc(sn_buffer, bytesread+count+remaining+1); +- memcpy(sn_buffer+bytesread, portion, count); ++ memcpy(sn_buffer + bytesread, portion, count); + if (portion) { XFree(portion); portion = 0; } + bytesread += count; + // Cannot trust data to be null terminated diff --git a/SPECS/fltk.spec b/SPECS/fltk.spec index 240ef47..73f767b 100644 --- a/SPECS/fltk.spec +++ b/SPECS/fltk.spec @@ -2,7 +2,7 @@ Summary: C++ user interface toolkit Name: fltk Version: 1.3.4 -Release: 2%{?dist} +Release: 3%{?dist} # see COPYING (or http://www.fltk.org/COPYING.php ) for exceptions details License: LGPLv2+ with exceptions @@ -13,6 +13,8 @@ Source1: fltk-config.sh ## FIXME/TODO: upstream these asap -- Rex Patch1: fltk-1.3.4-fltk_config.patch Patch2: fltk-1.3.4-fluid.patch +Patch3: fltk-1.3.4-fix-segfault-if-using-very-large-selections.patch +Patch4: fltk-1.3.4-improve-x11-selection-data-transfer-protocol.patch BuildRequires: desktop-file-utils BuildRequires: libjpeg-devel @@ -61,6 +63,8 @@ Requires: %{name}-devel %patch1 -p1 -b .fltk_config %patch2 -p1 -b .fluid +%patch3 -p1 -b .fix-segfault-if-using-very-large-selections +%patch4 -p1 -b .improve-x11-selection-data-transfer-protocol # verbose build output sed -i.silent '\,^.SILENT:,d' makeinclude.in @@ -164,6 +168,10 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &> /dev/null || : %changelog +* Mon Jul 11 2022 Jan Grulich - 1.3.4-3 +- Fix segfault if using very large selections + Resolves: bz#1999819 + * Thu Feb 20 2020 Jan Grulich - 1.3.4-2 - Do not drop linker flags for main library when --use-xxx option is used Resolves: bz#1510482