To: vim_dev@googlegroups.com Subject: Patch 8.0.0737 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.0737 Problem: Crash when X11 selection is very big. Solution: Use static items instead of allocating them. Add callbacks. (Ozaki Kiichi) Files: src/testdir/shared.vim, src/testdir/test_quotestar.vim, src/ui.c *** ../vim-8.0.0736/src/testdir/shared.vim 2017-03-18 16:18:25.099693814 +0100 --- src/testdir/shared.vim 2017-07-19 19:16:11.235499909 +0200 *************** *** 111,124 **** " 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) " 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) try if eval(a:expr) if has('reltime') --- 111,125 ---- " 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, ...) ! 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(timeout / 10) try if eval(a:expr) if has('reltime') *************** *** 133,139 **** endif sleep 10m endfor ! return 1000 endfunc " Wait for up to a given milliseconds. --- 134,140 ---- endif sleep 10m endfor ! return timeout endfunc " Wait for up to a given milliseconds. *** ../vim-8.0.0736/src/testdir/test_quotestar.vim 2017-06-10 16:30:27.965876961 +0200 --- src/testdir/test_quotestar.vim 2017-07-19 19:16:11.235499909 +0200 *************** *** 88,93 **** --- 88,105 ---- 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 @* = '' *** ../vim-8.0.0736/src/ui.c 2017-03-29 19:20:25.385015086 +0200 --- src/ui.c 2017-07-19 19:26:34.987051580 +0200 *************** *** 2042,2051 **** * 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 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 *); /* * Property callback to get a timestamp for XtOwnSelection. --- 2042,2052 ---- * X Selection stuff, for cutting and pasting text to other windows. */ ! 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 w, XtPointer success, Atom *sel_atom, Atom *type, XtPointer value, long_u *length, int *format); /* * Property callback to get a timestamp for XtOwnSelection. *************** *** 2085,2091 **** /* 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) { /* Set the "owned" flag now, there may have been a call to * lose_ownership_cb in between. */ --- 2086,2092 ---- /* Get the selection, using the event timestamp. */ if (XtOwnSelection(w, xproperty->atom, xproperty->time, clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb, ! clip_x11_notify_cb) == OK) { /* Set the "owned" flag now, there may have been a call to * lose_ownership_cb in between. */ *************** *** 2276,2284 **** start_time = time(NULL); while (success == MAYBE) { ! if (XCheckTypedEvent(dpy, SelectionNotify, &event) ! || XCheckTypedEvent(dpy, SelectionRequest, &event) ! || XCheckTypedEvent(dpy, PropertyNotify, &event)) { /* This is where clip_x11_request_selection_cb() should be * called. It may actually happen a bit later, so we loop --- 2277,2285 ---- start_time = time(NULL); while (success == MAYBE) { ! 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,2341 **** long_u *length, int *format) { ! char_u *string; ! char_u *result; ! int motion_type; ! VimClipboard *cbd; ! int i; if (*sel_atom == clip_plus.sel_atom) cbd = &clip_plus; --- 2332,2343 ---- long_u *length, int *format) { ! 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,2357 **** /* requestor wants to know what target types we support */ if (*target == targets_atom) { ! Atom *array; - if ((array = (Atom *)XtMalloc((unsigned)(sizeof(Atom) * 7))) == NULL) - return False; *value = (XtPointer)array; i = 0; array[i++] = targets_atom; --- 2350,2357 ---- /* requestor wants to know what target types we support */ if (*target == targets_atom) { ! static Atom array[7]; *value = (XtPointer)array; i = 0; array[i++] = targets_atom; *************** *** 2400,2412 **** *length += STRLEN(p_enc) + 2; #endif ! *value = XtMalloc((Cardinal)*length); ! result = (char_u *)*value; ! if (result == NULL) { vim_free(string); return False; } if (*target == XA_STRING #ifdef FEAT_MBYTE --- 2400,2416 ---- *length += STRLEN(p_enc) + 2; #endif ! 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,2426 **** #endif ) { ! mch_memmove(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); int conv_result; /* create NUL terminated string which XmbTextListToTextProperty wants */ --- 2418,2430 ---- #endif ) { ! 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 *)save_result; int conv_result; /* create NUL terminated string which XmbTextListToTextProperty wants */ *************** *** 2428,2435 **** 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); --- 2432,2437 ---- *************** *** 2438,2461 **** *value = (XtPointer)(text_prop.value); /* from plain text */ *length = text_prop.nitems; *type = compound_text_atom; } - #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)); *type = vimenc_atom; } #endif - else { ! result[0] = motion_type; ! mch_memmove(result + 1, string, (size_t)(*length - 1)); *type = vim_atom; } *format = 8; /* 8 bits per char */ --- 2440,2464 ---- *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); ! 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 { ! 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,2484 **** --- 2482,2493 ---- 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,2498 **** if (XtOwnSelection(myShell, cbd->sel_atom, XtLastTimestampProcessed(XtDisplay(myShell)), clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb, ! NULL) == False) return FAIL; } else --- 2501,2507 ---- if (XtOwnSelection(myShell, cbd->sel_atom, XtLastTimestampProcessed(XtDisplay(myShell)), clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb, ! clip_x11_notify_cb) == False) return FAIL; } else *** ../vim-8.0.0736/src/version.c 2017-07-19 18:18:27.828135659 +0200 --- src/version.c 2017-07-19 19:18:49.030374635 +0200 *************** *** 771,772 **** --- 771,774 ---- { /* Add new patch number below this line */ + /**/ + 737, /**/ -- A computer program does what you tell it to do, not what you want it to do. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///