From 27a205e90fe95de78eddbc46e788881e5cafaf40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 13 Apr 2020 11:42:10 +0200 Subject: [PATCH] term: reset: plug memory leak In reset, we allocated new rows for all the currently visible lines. We did **not** however, free the 'old' rows. Fix by not explicitly allocating new rows, but instead allocating uninitialized rows when needed, and then explicitly erasing the row. If there already was a row allocated, it is simply erased. If there wasn't, the a new line is malloc:ed, and then erased. --- CHANGELOG.md | 1 + terminal.c | 58 ++++++++++++++++++++++++++++------------------------ 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a336623..59fa0535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ * OSC 4 with multiple `c;spec` pairs. * Alt+Return to emit "ESC \r". * Trackpad sloooow scrolling to eventually scroll a line. +* Memory leak in terminal reset. ### Security diff --git a/terminal.c b/terminal.c index c948c314..8c0ec60c 100644 --- a/terminal.c +++ b/terminal.c @@ -1106,6 +1106,31 @@ term_destroy(struct terminal *term) return ret; } +static inline void +erase_cell_range(struct terminal *term, struct row *row, int start, int end) +{ + assert(start < term->cols); + assert(end < term->cols); + + if (unlikely(term->vt.attrs.have_bg)) { + for (int col = start; col <= end; col++) { + struct cell *c = &row->cells[col]; + c->wc = 0; + c->attrs = (struct attributes){.have_bg = 1, .bg = term->vt.attrs.bg}; + } + } else + memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0])); + + row->dirty = true; +} + +static inline void +erase_line(struct terminal *term, struct row *row) +{ + erase_cell_range(term, row, 0, term->cols - 1); + row->linebreak = false; +} + void term_reset(struct terminal *term, bool hard) { @@ -1175,8 +1200,12 @@ term_reset(struct terminal *term, bool hard) term->normal.offset = term->normal.view = 0; term->alt.offset = term->alt.view = 0; for (size_t i = 0; i < term->rows; i++) { - term->normal.rows[i] = grid_row_alloc(term->cols, true); - term->alt.rows[i] = grid_row_alloc(term->cols, true); + struct row *r = grid_row_and_alloc(&term->normal, i); + erase_line(term, r); + } + for (size_t i = 0; i < term->rows; i++) { + struct row *r = grid_row_and_alloc(&term->alt, i); + erase_line(term, r); } for (size_t i = term->rows; i < term->normal.num_rows; i++) { grid_row_free(term->normal.rows[i]); @@ -1356,31 +1385,6 @@ term_damage_scroll(struct terminal *term, enum damage_type damage_type, tll_push_back(term->grid->scroll_damage, dmg); } -static inline void -erase_cell_range(struct terminal *term, struct row *row, int start, int end) -{ - assert(start < term->cols); - assert(end < term->cols); - - if (unlikely(term->vt.attrs.have_bg)) { - for (int col = start; col <= end; col++) { - struct cell *c = &row->cells[col]; - c->wc = 0; - c->attrs = (struct attributes){.have_bg = 1, .bg = term->vt.attrs.bg}; - } - } else - memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0])); - - row->dirty = true; -} - -static inline void -erase_line(struct terminal *term, struct row *row) -{ - erase_cell_range(term, row, 0, term->cols - 1); - row->linebreak = false; -} - void term_erase(struct terminal *term, const struct coord *start, const struct coord *end) {