]> granicus.if.org Git - vim/commitdiff
patch 8.0.0737: crash when X11 selection is very big v8.0.0737
authorBram Moolenaar <Bram@vim.org>
Wed, 19 Jul 2017 17:55:58 +0000 (19:55 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 19 Jul 2017 17:55:58 +0000 (19:55 +0200)
Problem:    Crash when X11 selection is very big.
Solution:   Use static items instead of allocating them.  Add callbacks.
            (Ozaki Kiichi)

src/testdir/shared.vim
src/testdir/test_quotestar.vim
src/ui.c
src/version.c

index e28d162b84d8dfd73b18b4bc4e071f72df4887d3..790b07b564c8ad571fa0ec9444f0dd884b400ae5 100644 (file)
@@ -111,14 +111,15 @@ endfunc
 " Wait for up to a second for "expr" to become true.
 " Return time slept in milliseconds.  With the +reltime feature this can be
 " more than the actual waiting time.  Without +reltime it can also be less.
-func WaitFor(expr)
+func WaitFor(expr, ...)
+  let timeout = get(a:000, 0, 1000)
   " using reltime() is more accurate, but not always available
   if has('reltime')
     let start = reltime()
   else
     let slept = 0
   endif
-  for i in range(100)
+  for i in range(timeout / 10)
     try
       if eval(a:expr)
        if has('reltime')
@@ -133,7 +134,7 @@ func WaitFor(expr)
     endif
     sleep 10m
   endfor
-  return 1000
+  return timeout
 endfunc
 
 " Wait for up to a given milliseconds.
index b053260be31fd8a9e78cc2cc95b1e828602fefcd..b7d31583d4c7f0d39fcf79c5c22a1ae56670b383 100644 (file)
@@ -88,6 +88,18 @@ func Do_test_quotestar_for_x11()
   call WaitFor('@* == "yes"')
   call assert_equal('yes', @*)
 
+  " Handle the large selection over 262040 byte.
+  let length = 262044
+  let sample = 'a' . repeat('b', length - 2) . 'c'
+  let @* = sample
+  call WaitFor('remote_expr("' . name . '", "len(@*) >= ' . length . '", "", 1)', 3000)
+  let res = remote_expr(name, "@*", "", 2)
+  call assert_equal(length, len(res))
+  " Check length to prevent a large amount of output at assertion failure.
+  if length == len(res)
+    call assert_equal(sample, res)
+  endif
+
   if has('unix') && has('gui') && !has('gui_running')
     let @* = ''
 
index 8691ab741a4da87b49107f0110e3ac9be209feee..90e961cac210624224814a6d58d4ea64a1bb383c 100644 (file)
--- a/src/ui.c
+++ b/src/ui.c
@@ -2042,10 +2042,11 @@ x11_setup_atoms(Display *dpy)
  * X Selection stuff, for cutting and pasting text to other windows.
  */
 
-static Boolean clip_x11_convert_selection_cb(Widget, Atom *, Atom *, Atom *, XtPointer *, long_u *, int *);
-static void  clip_x11_lose_ownership_cb(Widget, Atom *);
+static Boolean clip_x11_convert_selection_cb(Widget w, Atom *sel_atom, Atom *target, Atom *type, XtPointer *value, long_u *length, int *format);
+static void clip_x11_lose_ownership_cb(Widget w, Atom *sel_atom);
+static void clip_x11_notify_cb(Widget w, Atom *sel_atom, Atom *target);
 static void clip_x11_timestamp_cb(Widget w, XtPointer n, XEvent *event, Boolean *cont);
-static void  clip_x11_request_selection_cb(Widget, XtPointer, Atom *, Atom *, XtPointer, long_u *, int *);
+static void clip_x11_request_selection_cb(Widget w, XtPointer success, Atom *sel_atom, Atom *type, XtPointer value, long_u *length, int *format);
 
 /*
  * Property callback to get a timestamp for XtOwnSelection.
@@ -2085,7 +2086,7 @@ clip_x11_timestamp_cb(
     /* Get the selection, using the event timestamp. */
     if (XtOwnSelection(w, xproperty->atom, xproperty->time,
            clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
-           NULL) == OK)
+           clip_x11_notify_cb) == OK)
     {
        /* Set the "owned" flag now, there may have been a call to
         * lose_ownership_cb in between. */
@@ -2276,9 +2277,9 @@ clip_x11_request_selection(
        start_time = time(NULL);
        while (success == MAYBE)
        {
-           if (XCheckTypedEvent(dpy, SelectionNotify, &event)
-                   || XCheckTypedEvent(dpy, SelectionRequest, &event)
-                   || XCheckTypedEvent(dpy, PropertyNotify, &event))
+           if (XCheckTypedEvent(dpy, PropertyNotify, &event)
+                   || XCheckTypedEvent(dpy, SelectionNotify, &event)
+                   || XCheckTypedEvent(dpy, SelectionRequest, &event))
            {
                /* This is where clip_x11_request_selection_cb() should be
                 * called.  It may actually happen a bit later, so we loop
@@ -2331,11 +2332,12 @@ clip_x11_convert_selection_cb(
     long_u     *length,
     int                *format)
 {
-    char_u     *string;
-    char_u     *result;
-    int                motion_type;
-    VimClipboard       *cbd;
-    int                i;
+    static char_u   *save_result = NULL;
+    static long_u   save_length = 0;
+    char_u         *string;
+    int                    motion_type;
+    VimClipboard    *cbd;
+    int                    i;
 
     if (*sel_atom == clip_plus.sel_atom)
        cbd = &clip_plus;
@@ -2348,10 +2350,8 @@ clip_x11_convert_selection_cb(
     /* requestor wants to know what target types we support */
     if (*target == targets_atom)
     {
-       Atom *array;
+       static Atom array[7];
 
-       if ((array = (Atom *)XtMalloc((unsigned)(sizeof(Atom) * 7))) == NULL)
-           return False;
        *value = (XtPointer)array;
        i = 0;
        array[i++] = targets_atom;
@@ -2400,13 +2400,17 @@ clip_x11_convert_selection_cb(
        *length += STRLEN(p_enc) + 2;
 #endif
 
-    *value = XtMalloc((Cardinal)*length);
-    result = (char_u *)*value;
-    if (result == NULL)
+    if (save_length < *length || save_length / 2 >= *length)
+       *value = XtRealloc((char *)save_result, (Cardinal)*length + 1);
+    else
+       *value = save_result;
+    if (*value == NULL)
     {
        vim_free(string);
        return False;
     }
+    save_result = (char_u *)*value;
+    save_length = *length;
 
     if (*target == XA_STRING
 #ifdef FEAT_MBYTE
@@ -2414,13 +2418,13 @@ clip_x11_convert_selection_cb(
 #endif
            )
     {
-       mch_memmove(result, string, (size_t)(*length));
+       mch_memmove(save_result, string, (size_t)(*length));
        *type = *target;
     }
     else if (*target == compound_text_atom || *target == text_atom)
     {
        XTextProperty   text_prop;
-       char            *string_nt = (char *)alloc((unsigned)*length + 1);
+       char            *string_nt = (char *)save_result;
        int             conv_result;
 
        /* create NUL terminated string which XmbTextListToTextProperty wants */
@@ -2428,8 +2432,6 @@ clip_x11_convert_selection_cb(
        string_nt[*length] = NUL;
        conv_result = XmbTextListToTextProperty(X_DISPLAY, (char **)&string_nt,
                                           1, XCompoundTextStyle, &text_prop);
-       vim_free(string_nt);
-       XtFree(*value);                 /* replace with COMPOUND text */
        if (conv_result != Success)
        {
            vim_free(string);
@@ -2438,24 +2440,25 @@ clip_x11_convert_selection_cb(
        *value = (XtPointer)(text_prop.value);  /*    from plain text */
        *length = text_prop.nitems;
        *type = compound_text_atom;
+       XtFree((char *)save_result);
+       save_result = (char_u *)*value;
+       save_length = *length;
     }
-
 #ifdef FEAT_MBYTE
     else if (*target == vimenc_atom)
     {
        int l = STRLEN(p_enc);
 
-       result[0] = motion_type;
-       STRCPY(result + 1, p_enc);
-       mch_memmove(result + l + 2, string, (size_t)(*length - l - 2));
+       save_result[0] = motion_type;
+       STRCPY(save_result + 1, p_enc);
+       mch_memmove(save_result + l + 2, string, (size_t)(*length - l - 2));
        *type = vimenc_atom;
     }
 #endif
-
     else
     {
-       result[0] = motion_type;
-       mch_memmove(result + 1, string, (size_t)(*length - 1));
+       save_result[0] = motion_type;
+       mch_memmove(save_result + 1, string, (size_t)(*length - 1));
        *type = vim_atom;
     }
     *format = 8;           /* 8 bits per char */
@@ -2479,6 +2482,12 @@ clip_x11_lose_selection(Widget myShell, VimClipboard *cbd)
                                XtLastTimestampProcessed(XtDisplay(myShell)));
 }
 
+    static void
+clip_x11_notify_cb(Widget w UNUSED, Atom *sel_atom UNUSED, Atom *target UNUSED)
+{
+    /* To prevent automatically freeing the selection value. */
+}
+
     int
 clip_x11_own_selection(Widget myShell, VimClipboard *cbd)
 {
@@ -2492,7 +2501,7 @@ clip_x11_own_selection(Widget myShell, VimClipboard *cbd)
        if (XtOwnSelection(myShell, cbd->sel_atom,
               XtLastTimestampProcessed(XtDisplay(myShell)),
               clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
-              NULL) == False)
+              clip_x11_notify_cb) == False)
            return FAIL;
     }
     else
index d5e383efd1254ae816b0c1012d127dcddd1028df..9921ec697b3f7ddbdd5a3d58bce57a37e658dcc8 100644 (file)
@@ -769,6 +769,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    737,
 /**/
     736,
 /**/