Fix a latent bug in print_wchar
authorTom Tromey <tom@tromey.com>
Sun, 13 Feb 2022 01:41:34 +0000 (18:41 -0700)
committerTom Tromey <tom@tromey.com>
Mon, 10 Oct 2022 16:43:34 +0000 (10:43 -0600)
print_wchar keeps track of when escape sequences are emitted, to force
an escape sequence if needed by a subsequent character.  For example
for the string concatenation "\0" "1", gdb will print "\000\061" --
because printing "\0001" might be confusing.

However, this code has two errors.  First, this logic is not needed
for octal escapes, because there is a length limit of 3 for octal
escapes, and gdb always prints these with "%.3o".  Second, though,
this *is* needed for hex escapes, because those do not have a length
limit.

This patch fixes these problems and adds the appropriate tests.

gdb/gdb_wchar.h
gdb/testsuite/gdb.base/charset.exp
gdb/valprint.c

index ba5baf3a2a09f933a093e0f726afc52b8189d410..8c6e4fc9fd6cf75c706dc1e09058db798c7ab16c 100644 (file)
@@ -66,7 +66,7 @@ typedef wint_t gdb_wint_t;
 
 #define gdb_wcslen wcslen
 #define gdb_iswprint iswprint
-#define gdb_iswdigit iswdigit
+#define gdb_iswxdigit iswxdigit
 #define gdb_btowc btowc
 #define gdb_WEOF WEOF
 
@@ -103,7 +103,7 @@ typedef int gdb_wint_t;
 
 #define gdb_wcslen strlen
 #define gdb_iswprint isprint
-#define gdb_iswdigit isdigit
+#define gdb_iswxdigit isxdigit
 #define gdb_btowc /* empty */
 #define gdb_WEOF EOF
 
index 5df2ec1a8de0585ac89c76e2a9f4b60b27a4cc97..359968df6967ecc06ba23d266a6f31312833ec86 100644 (file)
@@ -503,6 +503,11 @@ gdb_test "print '\\9'" " = \[0-9\]+ '9'"
 # An octal escape can only be 3 digits.
 gdb_test "print \"\\1011\"" " = \"A1\""
 
+# The final digit does not need to be escaped here.
+foreach val {0 1 2 3 4 5 6 7 8 9 a b c d e f} {
+    gdb_test "print \"\\0\" \"${val}\"" " = \"\\\\000${val}\""
+}
+
 # Tests for wide- or unicode- strings.  L is the prefix letter to use,
 # either "L" (for wide strings), "u" (for UTF-16), or "U" (for UTF-32).
 # NAME is used in the test names and should be related to the prefix
@@ -519,6 +524,9 @@ proc test_wide_or_unicode {L name} {
     gdb_test "print $L\"\" \"abcdef\" \"g\"" \
       "$L\"abcdefg\"" \
       "concatenate three strings with empty $name string"
+    gdb_test "print $L\"\\xffef\" $L\"f\"" \
+       "$L\"\\\\xffef\\\\146\"" \
+       "test multi-char escape sequence case for $name"
 
     gdb_test "print $L'a'" "= \[0-9\]+ $L'a'" \
       "basic $name character"
index 5a2f4dfc62a569d41dfe79317c4647a2b4db8b90..f079f31fa7bf0720a93b7d0bb4690032dd9d4d96 100644 (file)
@@ -2108,9 +2108,7 @@ print_wchar (gdb_wint_t w, const gdb_byte *orig,
        break;
       default:
        {
-         if (gdb_iswprint (w) && (!need_escape || (!gdb_iswdigit (w)
-                                                   && w != LCST ('8')
-                                                   && w != LCST ('9'))))
+         if (gdb_iswprint (w) && !(need_escape && gdb_iswxdigit (w)))
            {
              gdb_wchar_t wchar = w;
 
@@ -2132,10 +2130,19 @@ print_wchar (gdb_wint_t w, const gdb_byte *orig,
                  /* If the value fits in 3 octal digits, print it that
                     way.  Otherwise, print it as a hex escape.  */
                  if (value <= 0777)
-                   xsnprintf (octal, sizeof (octal), "\\%.3o",
-                              (int) (value & 0777));
+                   {
+                     xsnprintf (octal, sizeof (octal), "\\%.3o",
+                                (int) (value & 0777));
+                     *need_escapep = false;
+                   }
                  else
-                   xsnprintf (octal, sizeof (octal), "\\x%lx", (long) value);
+                   {
+                     xsnprintf (octal, sizeof (octal), "\\x%lx", (long) value);
+                     /* A hex escape might require the next character
+                        to be escaped, because, unlike with octal,
+                        hex escapes have no length limit.  */
+                     *need_escapep = true;
+                   }
                  append_string_as_wide (octal, output);
                }
              /* If we somehow have extra bytes, print them now.  */
@@ -2144,11 +2151,10 @@ print_wchar (gdb_wint_t w, const gdb_byte *orig,
                  char octal[5];
 
                  xsnprintf (octal, sizeof (octal), "\\%.3o", orig[i] & 0xff);
+                 *need_escapep = false;
                  append_string_as_wide (octal, output);
                  ++i;
                }
-
-             *need_escapep = true;
            }
          break;
        }