0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

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)
This commit is contained in:
Bram Moolenaar
2017-07-19 19:55:58 +02:00
parent 04f62f881c
commit cdb7e1b7f9
4 changed files with 57 additions and 33 deletions

View File

@@ -111,14 +111,15 @@ endfunc
" Wait for up to a second for "expr" to become true. " Wait for up to a second for "expr" to become true.
" Return time slept in milliseconds. With the +reltime feature this can be " 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. " 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 " using reltime() is more accurate, but not always available
if has('reltime') if has('reltime')
let start = reltime() let start = reltime()
else else
let slept = 0 let slept = 0
endif endif
for i in range(100) for i in range(timeout / 10)
try try
if eval(a:expr) if eval(a:expr)
if has('reltime') if has('reltime')
@@ -133,7 +134,7 @@ func WaitFor(expr)
endif endif
sleep 10m sleep 10m
endfor endfor
return 1000 return timeout
endfunc endfunc
" Wait for up to a given milliseconds. " Wait for up to a given milliseconds.

View File

@@ -88,6 +88,18 @@ func Do_test_quotestar_for_x11()
call WaitFor('@* == "yes"') call WaitFor('@* == "yes"')
call assert_equal('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') if has('unix') && has('gui') && !has('gui_running')
let @* = '' let @* = ''

View File

@@ -2042,10 +2042,11 @@ x11_setup_atoms(Display *dpy)
* X Selection stuff, for cutting and pasting text to other windows. * 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 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, Atom *); 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_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. * Property callback to get a timestamp for XtOwnSelection.
@@ -2085,7 +2086,7 @@ clip_x11_timestamp_cb(
/* Get the selection, using the event timestamp. */ /* Get the selection, using the event timestamp. */
if (XtOwnSelection(w, xproperty->atom, xproperty->time, if (XtOwnSelection(w, xproperty->atom, xproperty->time,
clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb, 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 /* Set the "owned" flag now, there may have been a call to
* lose_ownership_cb in between. */ * lose_ownership_cb in between. */
@@ -2276,9 +2277,9 @@ clip_x11_request_selection(
start_time = time(NULL); start_time = time(NULL);
while (success == MAYBE) while (success == MAYBE)
{ {
if (XCheckTypedEvent(dpy, SelectionNotify, &event) if (XCheckTypedEvent(dpy, PropertyNotify, &event)
|| XCheckTypedEvent(dpy, SelectionRequest, &event) || XCheckTypedEvent(dpy, SelectionNotify, &event)
|| XCheckTypedEvent(dpy, PropertyNotify, &event)) || XCheckTypedEvent(dpy, SelectionRequest, &event))
{ {
/* This is where clip_x11_request_selection_cb() should be /* This is where clip_x11_request_selection_cb() should be
* called. It may actually happen a bit later, so we loop * called. It may actually happen a bit later, so we loop
@@ -2331,11 +2332,12 @@ clip_x11_convert_selection_cb(
long_u *length, long_u *length,
int *format) int *format)
{ {
char_u *string; static char_u *save_result = NULL;
char_u *result; static long_u save_length = 0;
int motion_type; char_u *string;
VimClipboard *cbd; int motion_type;
int i; VimClipboard *cbd;
int i;
if (*sel_atom == clip_plus.sel_atom) if (*sel_atom == clip_plus.sel_atom)
cbd = &clip_plus; cbd = &clip_plus;
@@ -2348,10 +2350,8 @@ clip_x11_convert_selection_cb(
/* requestor wants to know what target types we support */ /* requestor wants to know what target types we support */
if (*target == targets_atom) if (*target == targets_atom)
{ {
Atom *array; static Atom array[7];
if ((array = (Atom *)XtMalloc((unsigned)(sizeof(Atom) * 7))) == NULL)
return False;
*value = (XtPointer)array; *value = (XtPointer)array;
i = 0; i = 0;
array[i++] = targets_atom; array[i++] = targets_atom;
@@ -2400,13 +2400,17 @@ clip_x11_convert_selection_cb(
*length += STRLEN(p_enc) + 2; *length += STRLEN(p_enc) + 2;
#endif #endif
*value = XtMalloc((Cardinal)*length); if (save_length < *length || save_length / 2 >= *length)
result = (char_u *)*value; *value = XtRealloc((char *)save_result, (Cardinal)*length + 1);
if (result == NULL) else
*value = save_result;
if (*value == NULL)
{ {
vim_free(string); vim_free(string);
return False; return False;
} }
save_result = (char_u *)*value;
save_length = *length;
if (*target == XA_STRING if (*target == XA_STRING
#ifdef FEAT_MBYTE #ifdef FEAT_MBYTE
@@ -2414,13 +2418,13 @@ clip_x11_convert_selection_cb(
#endif #endif
) )
{ {
mch_memmove(result, string, (size_t)(*length)); mch_memmove(save_result, string, (size_t)(*length));
*type = *target; *type = *target;
} }
else if (*target == compound_text_atom || *target == text_atom) else if (*target == compound_text_atom || *target == text_atom)
{ {
XTextProperty text_prop; XTextProperty text_prop;
char *string_nt = (char *)alloc((unsigned)*length + 1); char *string_nt = (char *)save_result;
int conv_result; int conv_result;
/* create NUL terminated string which XmbTextListToTextProperty wants */ /* create NUL terminated string which XmbTextListToTextProperty wants */
@@ -2428,8 +2432,6 @@ clip_x11_convert_selection_cb(
string_nt[*length] = NUL; string_nt[*length] = NUL;
conv_result = XmbTextListToTextProperty(X_DISPLAY, (char **)&string_nt, conv_result = XmbTextListToTextProperty(X_DISPLAY, (char **)&string_nt,
1, XCompoundTextStyle, &text_prop); 1, XCompoundTextStyle, &text_prop);
vim_free(string_nt);
XtFree(*value); /* replace with COMPOUND text */
if (conv_result != Success) if (conv_result != Success)
{ {
vim_free(string); vim_free(string);
@@ -2438,24 +2440,25 @@ clip_x11_convert_selection_cb(
*value = (XtPointer)(text_prop.value); /* from plain text */ *value = (XtPointer)(text_prop.value); /* from plain text */
*length = text_prop.nitems; *length = text_prop.nitems;
*type = compound_text_atom; *type = compound_text_atom;
XtFree((char *)save_result);
save_result = (char_u *)*value;
save_length = *length;
} }
#ifdef FEAT_MBYTE #ifdef FEAT_MBYTE
else if (*target == vimenc_atom) else if (*target == vimenc_atom)
{ {
int l = STRLEN(p_enc); int l = STRLEN(p_enc);
result[0] = motion_type; save_result[0] = motion_type;
STRCPY(result + 1, p_enc); STRCPY(save_result + 1, p_enc);
mch_memmove(result + l + 2, string, (size_t)(*length - l - 2)); mch_memmove(save_result + l + 2, string, (size_t)(*length - l - 2));
*type = vimenc_atom; *type = vimenc_atom;
} }
#endif #endif
else else
{ {
result[0] = motion_type; save_result[0] = motion_type;
mch_memmove(result + 1, string, (size_t)(*length - 1)); mch_memmove(save_result + 1, string, (size_t)(*length - 1));
*type = vim_atom; *type = vim_atom;
} }
*format = 8; /* 8 bits per char */ *format = 8; /* 8 bits per char */
@@ -2479,6 +2482,12 @@ clip_x11_lose_selection(Widget myShell, VimClipboard *cbd)
XtLastTimestampProcessed(XtDisplay(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 int
clip_x11_own_selection(Widget myShell, VimClipboard *cbd) 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, if (XtOwnSelection(myShell, cbd->sel_atom,
XtLastTimestampProcessed(XtDisplay(myShell)), XtLastTimestampProcessed(XtDisplay(myShell)),
clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb, clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
NULL) == False) clip_x11_notify_cb) == False)
return FAIL; return FAIL;
} }
else else

View File

@@ -769,6 +769,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
737,
/**/ /**/
736, 736,
/**/ /**/