Commit 3ddbea75 authored by Nicolas Pitre's avatar Nicolas Pitre Committed by Greg Kroah-Hartman
Browse files

vt: resize saved unicode buffer on alt screen exit after resize



Instead of discarding the saved unicode buffer when the console was
resized while in the alternate screen, resize it to the current
dimensions using vc_uniscr_copy_area() to preserve its content. This
properly restores the unicode screen on alt screen exit rather than
lazily rebuilding it from a lossy reverse glyph translation.

On allocation failure the stale buffer is freed and vc_uni_lines is
set to NULL so it gets lazily rebuilt via vc_uniscr_check() when next
needed.

Fixes: 40014493 ("vt: discard stale unicode buffer on alt screen exit after resize")
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarNicolas Pitre <nico@fluxnic.net>
Link: https://patch.msgid.link/3nsr334n-079q-125n-7807-n4nq818758ns@syhkavp.arg


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 40014493
Loading
Loading
Loading
Loading
+15 −9
Original line number Diff line number Diff line
@@ -1901,7 +1901,6 @@ static void leave_alt_screen(struct vc_data *vc)
	unsigned int rows = min(vc->vc_saved_rows, vc->vc_rows);
	unsigned int cols = min(vc->vc_saved_cols, vc->vc_cols);
	u16 *src, *dest;
	bool uni_lines_stale;

	if (vc->vc_saved_screen == NULL)
		return; /* Not inside an alt-screen */
@@ -1912,15 +1911,22 @@ static void leave_alt_screen(struct vc_data *vc)
	}
	/*
	 * If the console was resized while in the alternate screen,
	 * vc_saved_uni_lines was allocated for the old dimensions.
	 * Restoring it would cause out-of-bounds accesses. Discard it
	 * and let the unicode screen be lazily rebuilt.
	 * resize the saved unicode buffer to the current dimensions.
	 * On allocation failure new_uniscr is NULL, causing the old
	 * buffer to be freed and vc_uni_lines to be lazily rebuilt
	 * via vc_uniscr_check() when next needed.
	 */
	uni_lines_stale = vc->vc_saved_rows != vc->vc_rows ||
			  vc->vc_saved_cols != vc->vc_cols;
	if (uni_lines_stale)
	if (vc->vc_saved_uni_lines &&
	    (vc->vc_saved_rows != vc->vc_rows ||
	     vc->vc_saved_cols != vc->vc_cols)) {
		u32 **new_uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);

		if (new_uniscr)
			vc_uniscr_copy_area(new_uniscr, vc->vc_cols, vc->vc_rows,
					    vc->vc_saved_uni_lines, cols, 0, rows);
		vc_uniscr_free(vc->vc_saved_uni_lines);
	else
		vc->vc_saved_uni_lines = new_uniscr;
	}
	vc_uniscr_set(vc, vc->vc_saved_uni_lines);
	vc->vc_saved_uni_lines = NULL;
	restore_cur(vc);