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 -- Br...@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 ///