mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 8.1.0633: crash when out of memory while opening a terminal window
Problem: Crash when out of memory while opening a terminal window. Solution: Handle out-of-memory more gracefully.
This commit is contained in:
@@ -53,6 +53,8 @@ static VTermState *vterm_state_new(VTerm *vt)
|
|||||||
{
|
{
|
||||||
VTermState *state = vterm_allocator_malloc(vt, sizeof(VTermState));
|
VTermState *state = vterm_allocator_malloc(vt, sizeof(VTermState));
|
||||||
|
|
||||||
|
if (state == NULL)
|
||||||
|
return NULL;
|
||||||
state->vt = vt;
|
state->vt = vt;
|
||||||
|
|
||||||
state->rows = vt->rows;
|
state->rows = vt->rows;
|
||||||
@@ -1693,6 +1695,10 @@ static const VTermParserCallbacks parser_callbacks = {
|
|||||||
on_resize /* resize */
|
on_resize /* resize */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the existing state or create a new one.
|
||||||
|
* Returns NULL when out of memory.
|
||||||
|
*/
|
||||||
VTermState *vterm_obtain_state(VTerm *vt)
|
VTermState *vterm_obtain_state(VTerm *vt)
|
||||||
{
|
{
|
||||||
VTermState *state;
|
VTermState *state;
|
||||||
@@ -1700,6 +1706,8 @@ VTermState *vterm_obtain_state(VTerm *vt)
|
|||||||
return vt->state;
|
return vt->state;
|
||||||
|
|
||||||
state = vterm_state_new(vt);
|
state = vterm_state_new(vt);
|
||||||
|
if (state == NULL)
|
||||||
|
return NULL;
|
||||||
vt->state = state;
|
vt->state = state;
|
||||||
|
|
||||||
state->combine_chars_size = 16;
|
state->combine_chars_size = 16;
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#include "vterm_internal.h"
|
#include "vterm_internal.h"
|
||||||
|
|
||||||
|
/* vim: set sw=2 : */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -95,8 +96,7 @@ static ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(buffer)
|
vterm_allocator_free(screen->vt, buffer);
|
||||||
vterm_allocator_free(screen->vt, buffer);
|
|
||||||
|
|
||||||
return new_buffer;
|
return new_buffer;
|
||||||
}
|
}
|
||||||
@@ -518,8 +518,7 @@ static int resize(int new_rows, int new_cols, VTermPos *delta, void *user)
|
|||||||
screen->rows = new_rows;
|
screen->rows = new_rows;
|
||||||
screen->cols = new_cols;
|
screen->cols = new_cols;
|
||||||
|
|
||||||
if(screen->sb_buffer)
|
vterm_allocator_free(screen->vt, screen->sb_buffer);
|
||||||
vterm_allocator_free(screen->vt, screen->sb_buffer);
|
|
||||||
|
|
||||||
screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols);
|
screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols);
|
||||||
|
|
||||||
@@ -619,16 +618,21 @@ static VTermStateCallbacks state_cbs = {
|
|||||||
&setlineinfo /* setlineinfo */
|
&setlineinfo /* setlineinfo */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a new screen and return it.
|
||||||
|
* Return NULL when out of memory.
|
||||||
|
*/
|
||||||
static VTermScreen *screen_new(VTerm *vt)
|
static VTermScreen *screen_new(VTerm *vt)
|
||||||
{
|
{
|
||||||
VTermState *state = vterm_obtain_state(vt);
|
VTermState *state = vterm_obtain_state(vt);
|
||||||
VTermScreen *screen;
|
VTermScreen *screen;
|
||||||
int rows, cols;
|
int rows, cols;
|
||||||
|
|
||||||
if(!state)
|
if (state == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
screen = vterm_allocator_malloc(vt, sizeof(VTermScreen));
|
screen = vterm_allocator_malloc(vt, sizeof(VTermScreen));
|
||||||
|
if (screen == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
vterm_get_size(vt, &rows, &cols);
|
vterm_get_size(vt, &rows, &cols);
|
||||||
|
|
||||||
@@ -646,10 +650,13 @@ static VTermScreen *screen_new(VTerm *vt)
|
|||||||
screen->cbdata = NULL;
|
screen->cbdata = NULL;
|
||||||
|
|
||||||
screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols);
|
screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols);
|
||||||
|
|
||||||
screen->buffer = screen->buffers[0];
|
screen->buffer = screen->buffers[0];
|
||||||
|
|
||||||
screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols);
|
screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols);
|
||||||
|
if (screen->buffer == NULL || screen->sb_buffer == NULL)
|
||||||
|
{
|
||||||
|
vterm_screen_free(screen);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
vterm_state_set_callbacks(screen->state, &state_cbs, screen);
|
vterm_state_set_callbacks(screen->state, &state_cbs, screen);
|
||||||
|
|
||||||
@@ -659,11 +666,8 @@ static VTermScreen *screen_new(VTerm *vt)
|
|||||||
INTERNAL void vterm_screen_free(VTermScreen *screen)
|
INTERNAL void vterm_screen_free(VTermScreen *screen)
|
||||||
{
|
{
|
||||||
vterm_allocator_free(screen->vt, screen->buffers[0]);
|
vterm_allocator_free(screen->vt, screen->buffers[0]);
|
||||||
if(screen->buffers[1])
|
vterm_allocator_free(screen->vt, screen->buffers[1]);
|
||||||
vterm_allocator_free(screen->vt, screen->buffers[1]);
|
|
||||||
|
|
||||||
vterm_allocator_free(screen->vt, screen->sb_buffer);
|
vterm_allocator_free(screen->vt, screen->sb_buffer);
|
||||||
|
|
||||||
vterm_allocator_free(screen->vt, screen);
|
vterm_allocator_free(screen->vt, screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#define DEFINE_INLINES
|
#define DEFINE_INLINES
|
||||||
|
|
||||||
|
/* vim: set sw=2 : */
|
||||||
#include "vterm_internal.h"
|
#include "vterm_internal.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -41,6 +42,8 @@ VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *fun
|
|||||||
/* Need to bootstrap using the allocator function directly */
|
/* Need to bootstrap using the allocator function directly */
|
||||||
VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata);
|
VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata);
|
||||||
|
|
||||||
|
if (vt == NULL)
|
||||||
|
return NULL;
|
||||||
vt->allocator = funcs;
|
vt->allocator = funcs;
|
||||||
vt->allocdata = allocdata;
|
vt->allocdata = allocdata;
|
||||||
|
|
||||||
@@ -55,10 +58,21 @@ VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *fun
|
|||||||
vt->parser.strbuffer_len = 500; /* should be able to hold an OSC string */
|
vt->parser.strbuffer_len = 500; /* should be able to hold an OSC string */
|
||||||
vt->parser.strbuffer_cur = 0;
|
vt->parser.strbuffer_cur = 0;
|
||||||
vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len);
|
vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len);
|
||||||
|
if (vt->parser.strbuffer == NULL)
|
||||||
|
{
|
||||||
|
vterm_allocator_free(vt, vt);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
vt->outbuffer_len = 200;
|
vt->outbuffer_len = 200;
|
||||||
vt->outbuffer_cur = 0;
|
vt->outbuffer_cur = 0;
|
||||||
vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);
|
vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);
|
||||||
|
if (vt->outbuffer == NULL)
|
||||||
|
{
|
||||||
|
vterm_allocator_free(vt, vt->parser.strbuffer);
|
||||||
|
vterm_allocator_free(vt, vt);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return vt;
|
return vt;
|
||||||
}
|
}
|
||||||
@@ -82,9 +96,13 @@ INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
|
|||||||
return (*vt->allocator->malloc)(size, vt->allocdata);
|
return (*vt->allocator->malloc)(size, vt->allocdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free "ptr" unless it is NULL.
|
||||||
|
*/
|
||||||
INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
|
INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
|
||||||
{
|
{
|
||||||
(*vt->allocator->free)(ptr, vt->allocdata);
|
if (ptr)
|
||||||
|
(*vt->allocator->free)(ptr, vt->allocdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)
|
void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)
|
||||||
|
@@ -3430,6 +3430,7 @@ set_vterm_palette(VTerm *vterm, long_u *rgb)
|
|||||||
{
|
{
|
||||||
int index = 0;
|
int index = 0;
|
||||||
VTermState *state = vterm_obtain_state(vterm);
|
VTermState *state = vterm_obtain_state(vterm);
|
||||||
|
|
||||||
for (; index < 16; index++)
|
for (; index < 16; index++)
|
||||||
{
|
{
|
||||||
VTermColor color;
|
VTermColor color;
|
||||||
@@ -3703,8 +3704,9 @@ static VTermAllocatorFunctions vterm_allocator = {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new vterm and initialize it.
|
* Create a new vterm and initialize it.
|
||||||
|
* Return FAIL when out of memory.
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
create_vterm(term_T *term, int rows, int cols)
|
create_vterm(term_T *term, int rows, int cols)
|
||||||
{
|
{
|
||||||
VTerm *vterm;
|
VTerm *vterm;
|
||||||
@@ -3714,7 +3716,18 @@ create_vterm(term_T *term, int rows, int cols)
|
|||||||
|
|
||||||
vterm = vterm_new_with_allocator(rows, cols, &vterm_allocator, NULL);
|
vterm = vterm_new_with_allocator(rows, cols, &vterm_allocator, NULL);
|
||||||
term->tl_vterm = vterm;
|
term->tl_vterm = vterm;
|
||||||
|
if (vterm == NULL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
// Allocate screen and state here, so we can bail out if that fails.
|
||||||
|
state = vterm_obtain_state(vterm);
|
||||||
screen = vterm_obtain_screen(vterm);
|
screen = vterm_obtain_screen(vterm);
|
||||||
|
if (state == NULL || screen == NULL)
|
||||||
|
{
|
||||||
|
vterm_free(vterm);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
vterm_screen_set_callbacks(screen, &screen_callbacks, term);
|
vterm_screen_set_callbacks(screen, &screen_callbacks, term);
|
||||||
/* TODO: depends on 'encoding'. */
|
/* TODO: depends on 'encoding'. */
|
||||||
vterm_set_utf8(vterm, 1);
|
vterm_set_utf8(vterm, 1);
|
||||||
@@ -3722,7 +3735,7 @@ create_vterm(term_T *term, int rows, int cols)
|
|||||||
init_default_colors(term);
|
init_default_colors(term);
|
||||||
|
|
||||||
vterm_state_set_default_colors(
|
vterm_state_set_default_colors(
|
||||||
vterm_obtain_state(vterm),
|
state,
|
||||||
&term->tl_default_color.fg,
|
&term->tl_default_color.fg,
|
||||||
&term->tl_default_color.bg);
|
&term->tl_default_color.bg);
|
||||||
|
|
||||||
@@ -3746,9 +3759,10 @@ create_vterm(term_T *term, int rows, int cols)
|
|||||||
#else
|
#else
|
||||||
value.boolean = 0;
|
value.boolean = 0;
|
||||||
#endif
|
#endif
|
||||||
state = vterm_obtain_state(vterm);
|
|
||||||
vterm_state_set_termprop(state, VTERM_PROP_CURSORBLINK, &value);
|
vterm_state_set_termprop(state, VTERM_PROP_CURSORBLINK, &value);
|
||||||
vterm_state_set_unrecognised_fallbacks(state, &parser_fallbacks, term);
|
vterm_state_set_unrecognised_fallbacks(state, &parser_fallbacks, term);
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -5629,7 +5643,8 @@ term_and_job_init(
|
|||||||
vim_free(cwd_wchar);
|
vim_free(cwd_wchar);
|
||||||
vim_free(env_wchar);
|
vim_free(env_wchar);
|
||||||
|
|
||||||
create_vterm(term, term->tl_rows, term->tl_cols);
|
if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
|
||||||
|
goto failed;
|
||||||
|
|
||||||
#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
|
#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
|
||||||
if (opt->jo_set2 & JO2_ANSI_COLORS)
|
if (opt->jo_set2 & JO2_ANSI_COLORS)
|
||||||
@@ -5710,7 +5725,8 @@ create_pty_only(term_T *term, jobopt_T *options)
|
|||||||
char in_name[80], out_name[80];
|
char in_name[80], out_name[80];
|
||||||
channel_T *channel = NULL;
|
channel_T *channel = NULL;
|
||||||
|
|
||||||
create_vterm(term, term->tl_rows, term->tl_cols);
|
if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
vim_snprintf(in_name, sizeof(in_name), "\\\\.\\pipe\\vim-%d-in-%d",
|
vim_snprintf(in_name, sizeof(in_name), "\\\\.\\pipe\\vim-%d-in-%d",
|
||||||
GetCurrentProcessId(),
|
GetCurrentProcessId(),
|
||||||
@@ -5822,7 +5838,8 @@ term_and_job_init(
|
|||||||
jobopt_T *opt,
|
jobopt_T *opt,
|
||||||
jobopt_T *orig_opt UNUSED)
|
jobopt_T *orig_opt UNUSED)
|
||||||
{
|
{
|
||||||
create_vterm(term, term->tl_rows, term->tl_cols);
|
if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
|
#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
|
||||||
if (opt->jo_set2 & JO2_ANSI_COLORS)
|
if (opt->jo_set2 & JO2_ANSI_COLORS)
|
||||||
@@ -5844,7 +5861,8 @@ term_and_job_init(
|
|||||||
static int
|
static int
|
||||||
create_pty_only(term_T *term, jobopt_T *opt)
|
create_pty_only(term_T *term, jobopt_T *opt)
|
||||||
{
|
{
|
||||||
create_vterm(term, term->tl_rows, term->tl_cols);
|
if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
term->tl_job = job_alloc();
|
term->tl_job = job_alloc();
|
||||||
if (term->tl_job == NULL)
|
if (term->tl_job == NULL)
|
||||||
|
@@ -799,6 +799,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 */
|
||||||
|
/**/
|
||||||
|
633,
|
||||||
/**/
|
/**/
|
||||||
632,
|
632,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user