# HG changeset patch # User Christian Brabandt # Date 1500487203 -7200 # Node ID c3227699ad4d8487946ce34b2bfa96d485038918 # Parent 1bb52ba993d9b6b63dbf58cc2ce8e54a29911202 patch 8.0.0737: crash when X11 selection is very big commit https://github.com/vim/vim/commit/cdb7e1b7f9e18a7b165ff09103a9994f84966123 Author: Bram Moolenaar Date: Wed Jul 19 19:55:58 2017 +0200 patch 8.0.0737: crash when X11 selection is very big Problem: Crash when X11 selection is very big. Solution: Use static items instead of allocating them. Add callbacks. (Ozaki Kiichi) diff --git a/src/testdir/shared.vim b/src/testdir/shared.vim --- a/src/testdir/shared.vim +++ b/src/testdir/shared.vim @@ -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. diff --git a/src/testdir/test_quotestar.vim b/src/testdir/test_quotestar.vim --- a/src/testdir/test_quotestar.vim +++ b/src/testdir/test_quotestar.vim @@ -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 @* = '' diff --git a/src/ui.c b/src/ui.c --- 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, 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, V 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 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -770,6 +770,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 737, +/**/ 736, /**/ 735,