I have found an error scenario that leads to an infinite printing loop

chenwj <[email protected]> Thu, 29 Aug 2024 15:54:38 +0800 (CST)
Newsgroups gmane.comp.boot-loaders.grub.bugs
Message-ID <[email protected]>
Hi, I have found an error scenario that leads to an infinite printing loop. This scenario requires the following two commands to be present in grub.cfg: "set lang=zh_CN" and "terminal_output gfxterm", and it must also be retrieved through PXE. Attached is the patch to fix the issue.


Thank you for your attention, and I look forward to your response.
You can reach me through this email.


Chen Weijie
Tel: 18362375558
0001-term-Fix-the-calculation-on-character-width-when-set.patch (application/octet-stream, 3.1 KB)
From f415f038198cee6fcd9d16d228b85a6095a5c92f Mon Sep 17 00:00:00 2001
From: Chen Weijie <[email protected]>
Date: Mon, 5 Aug 2024 14:11:37 +0800
Subject: [PATCH] term: Fix the calculation on character width when setting
 LANG="zh_CN"

Under an environment with the simplified Chinese language support, BIOS
enables the PXE module to load GRUB bootstrap files, it will invoke the
grub_normal_parse_line() function to parse and execute the grub.cfg
file. The recursive error printing occurs as follows:

> ?????????cannot allocate pages???
> ?????????cannot allocate pages???
> ?????????cannot allocate pages???

The reason is that when GRUB executes the command "terminal_output
gfxterm" to set the terminal type, the width of characters cannot be
correctly calculated in calculate_normal_character_width() due to the
lack of consideration for simplified Chinese encoding support. This
leads to a recursive loop printing error behavior after GRUB calls the
grub_print_error() API function. This commit adds the simplified Chinese
support, fixes character calculation, and resolves this issue.

Signed-off-by: Chen Weijie <[email protected]>
Signed-off-by: Su Weiqiang <[email protected]>
Signed-off-by: Zhao Yihan <[email protected]>
---
 grub-core/term/gfxterm.c | 43 +++++++++++++++++++++++++++++-----------
 1 file changed, 31 insertions(+), 12 deletions(-)

diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c
index 3c468f459..1fb637de1 100644
--- a/grub-core/term/gfxterm.c
+++ b/grub-core/term/gfxterm.c
@@ -936,26 +936,45 @@ grub_gfxterm_putchar (struct grub_term_output *term,
     draw_cursor (1);
 }
 
-/* Use ASCII characters to determine normal character width.  */
+/* Iterate character width  */
 static unsigned int
-calculate_normal_character_width (grub_font_t font)
+iterate_character_width (grub_font_t font, unsigned int width, unsigned int start, unsigned int end)
 {
   struct grub_font_glyph *glyph;
-  unsigned int width = 0;
   unsigned int i;
 
+  for (i = start; i < end; i++) {
+    glyph = grub_font_get_glyph (font, i);
+
+    if (!glyph)
+      continue;
+
+    if (glyph->device_width > width)
+      width = glyph->device_width;
+  }
+
+  return width;
+}
+
+/* Use ASCII characters or simplified Chinese characters to determine 
+ * normal character width.  */
+static unsigned int
+calculate_normal_character_width (grub_font_t font)
+{
+  unsigned int width = 0;
+  const char *lang_name;
+
   /* Get properties of every printable ASCII character.  */
-  for (i = 32; i < 127; i++)
-    {
-      glyph = grub_font_get_glyph (font, i);
+  lang_name = grub_env_get ("lang");
 
-      /* Skip unknown characters.  Should never happen on normal conditions.  */
-      if (! glyph)
-	continue;
+  if (!grub_strcmp (lang_name, "zh_CN")) {
+    width = iterate_character_width (font, width, 0x3000, 0x3002);
+    width = iterate_character_width (font, width, 0x4E00, 0x9FFF);
+    width = iterate_character_width (font, width, 0xFF00, 0xFFEF);
+  }
+
+  width = iterate_character_width (font, width, 32, 127);
 
-      if (glyph->device_width > width)
-	width = glyph->device_width;
-    }
   if (!width)
     return 8;
 
-- 
2.24.3 (Apple Git-128)