• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1From 6caf952e48dbed40b5dcff01a94f57ba079b526c Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
3Date: Tue, 20 Sep 2022 18:06:35 +0200
4Subject: [PATCH] gregex: Use pcre2 error messages if we don't provide a
5 specific one
6
7In case we got a compilation or match error we should try to provide
8some useful error message, if possible, before returning a quite obscure
9"internal error" or "unknown error" string.
10
11So rely on PCRE2 strings even if they're not translated they can provide
12better information than the ones we're currently giving.
13
14Related to: https://gitlab.gnome.org/GNOME/glib/-/issues/2691
15Related to: https://gitlab.gnome.org/GNOME/glib/-/issues/2760
16
17Conflict:NA
18Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/6caf952e48dbed40b5dcff01a94f57ba079b526c
19
20---
21 glib/gregex.c      | 64 ++++++++++++++++++++++++++++++++++++++++------
22 glib/tests/regex.c |  2 ++
23 2 files changed, 58 insertions(+), 8 deletions(-)
24
25diff --git a/glib/gregex.c b/glib/gregex.c
26index 220a1a11ac..fcc28d62f4 100644
27--- a/glib/gregex.c
28+++ b/glib/gregex.c
29@@ -456,8 +456,25 @@ get_pcre2_bsr_match_options (GRegexMatchFlags match_flags)
30   return 0;
31 }
32
33+static char *
34+get_pcre2_error_string (int errcode)
35+{
36+  PCRE2_UCHAR8 error_msg[2048];
37+  int err_length;
38+
39+  err_length = pcre2_get_error_message (errcode, error_msg,
40+                                        G_N_ELEMENTS (error_msg));
41+
42+  if (err_length <= 0)
43+    return NULL;
44+
45+  /* The array is always filled with a trailing zero */
46+  g_assert ((size_t) err_length < G_N_ELEMENTS (error_msg));
47+  return g_memdup2 (error_msg, err_length + 1);
48+}
49+
50 static const gchar *
51-match_error (gint errcode)
52+translate_match_error (gint errcode)
53 {
54   switch (errcode)
55     {
56@@ -511,7 +528,24 @@ match_error (gint errcode)
57     default:
58       break;
59     }
60-  return _("unknown error");
61+  return NULL;
62+}
63+
64+static char *
65+get_match_error_message (int errcode)
66+{
67+  const char *msg = translate_match_error (errcode);
68+  char *error_string;
69+
70+  if (msg)
71+    return g_strdup (msg);
72+
73+  error_string = get_pcre2_error_string (errcode);
74+
75+  if (error_string)
76+    return error_string;
77+
78+  return g_strdup (_("unknown error"));
79 }
80
81 static void
82@@ -743,7 +777,6 @@ translate_compile_error (gint *errcode, const gchar **errmsg)
83     case PCRE2_ERROR_INTERNAL_BAD_CODE:
84     case PCRE2_ERROR_INTERNAL_BAD_CODE_IN_SKIP:
85       *errcode = G_REGEX_ERROR_INTERNAL;
86-      *errmsg = _("internal error");
87       break;
88     case PCRE2_ERROR_INVALID_SUBPATTERN_NAME:
89     case PCRE2_ERROR_CLASS_INVALID_RANGE:
90@@ -772,12 +805,10 @@ translate_compile_error (gint *errcode, const gchar **errmsg)
91     case PCRE2_ERROR_BAD_LITERAL_OPTIONS:
92     default:
93       *errcode = G_REGEX_ERROR_COMPILE;
94-      *errmsg = _("internal error");
95       break;
96     }
97
98   g_assert (*errcode != -1);
99-  g_assert (*errmsg != NULL);
100 }
101
102 /* GMatchInfo */
103@@ -1096,9 +1127,12 @@ g_match_info_next (GMatchInfo  *match_info,
104
105   if (IS_PCRE2_ERROR (match_info->matches))
106     {
107+      gchar *error_msg = get_match_error_message (match_info->matches);
108+
109       g_set_error (error, G_REGEX_ERROR, G_REGEX_ERROR_MATCH,
110                    _("Error while matching regular expression %s: %s"),
111-                   match_info->regex->pattern, match_error (match_info->matches));
112+                   match_info->regex->pattern, error_msg);
113+      g_clear_pointer (&error_msg, g_free);
114       return FALSE;
115     }
116   else if (match_info->matches == 0)
117@@ -1800,11 +1834,20 @@ regex_compile (const gchar  *pattern,
118     {
119       GError *tmp_error;
120       gchar *offset_str;
121+      gchar *pcre2_errmsg = NULL;
122+      int original_errcode;
123
124       /* Translate the PCRE error code to GRegexError and use a translated
125        * error message if possible */
126+      original_errcode = errcode;
127       translate_compile_error (&errcode, &errmsg);
128
129+      if (!errmsg)
130+        {
131+          errmsg = _("unknown error");
132+          pcre2_errmsg = get_pcre2_error_string (original_errcode);
133+        }
134+
135       /* PCRE uses byte offsets but we want to show character offsets */
136       erroffset = g_utf8_pointer_to_offset (pattern, &pattern[erroffset]);
137
138@@ -1812,9 +1855,11 @@ regex_compile (const gchar  *pattern,
139       tmp_error = g_error_new (G_REGEX_ERROR, errcode,
140                                _("Error while compiling regular expression ‘%s’ "
141                                  "at char %s: %s"),
142-                               pattern, offset_str, errmsg);
143+                               pattern, offset_str,
144+                               pcre2_errmsg ? pcre2_errmsg : errmsg);
145       g_propagate_error (error, tmp_error);
146       g_free (offset_str);
147+      g_clear_pointer (&pcre2_errmsg, g_free);
148
149       return NULL;
150     }
151@@ -2402,9 +2447,12 @@ g_regex_match_all_full (const GRegex      *regex,
152         }
153       else if (IS_PCRE2_ERROR (info->matches))
154         {
155+          gchar *error_msg = get_match_error_message (info->matches);
156+
157           g_set_error (error, G_REGEX_ERROR, G_REGEX_ERROR_MATCH,
158                        _("Error while matching regular expression %s: %s"),
159-                       regex->pattern, match_error (info->matches));
160+                       regex->pattern, error_msg);
161+          g_clear_pointer (&error_msg, g_free);
162         }
163       else if (info->matches != PCRE2_ERROR_NOMATCH)
164         {
165diff --git a/glib/tests/regex.c b/glib/tests/regex.c
166index 9803d49659..52af212f29 100644
167--- a/glib/tests/regex.c
168+++ b/glib/tests/regex.c
169@@ -2560,6 +2560,7 @@ main (int argc, char *argv[])
170   TEST_NEW_FAIL ("[a-z", 0, G_REGEX_ERROR_UNTERMINATED_CHARACTER_CLASS);
171   TEST_NEW_FAIL ("[\\B]", 0, G_REGEX_ERROR_INVALID_ESCAPE_IN_CHARACTER_CLASS);
172   TEST_NEW_FAIL ("[z-a]", 0, G_REGEX_ERROR_RANGE_OUT_OF_ORDER);
173+  TEST_NEW_FAIL ("^[[:alnum:]-_.]+$", 0, G_REGEX_ERROR_COMPILE);
174   TEST_NEW_FAIL ("{2,4}", 0, G_REGEX_ERROR_NOTHING_TO_REPEAT);
175   TEST_NEW_FAIL ("a(?u)", 0, G_REGEX_ERROR_UNRECOGNIZED_CHARACTER);
176   TEST_NEW_FAIL ("a(?<$foo)bar", 0, G_REGEX_ERROR_MISSING_SUBPATTERN_NAME);
177@@ -2636,6 +2637,7 @@ main (int argc, char *argv[])
178   TEST_MATCH_SIMPLE("a", "a", G_REGEX_CASELESS, 0, TRUE);
179   TEST_MATCH_SIMPLE("a", "A", G_REGEX_CASELESS, 0, TRUE);
180   TEST_MATCH_SIMPLE("\\C\\C", "ab", G_REGEX_OPTIMIZE | G_REGEX_RAW, 0, TRUE);
181+  TEST_MATCH_SIMPLE("^[[:alnum:]\\-_.]+$", "admin-foo", 0, 0, TRUE);
182   /* These are needed to test extended properties. */
183   TEST_MATCH_SIMPLE(AGRAVE, AGRAVE, G_REGEX_CASELESS, 0, TRUE);
184   TEST_MATCH_SIMPLE(AGRAVE, AGRAVE_UPPER, G_REGEX_CASELESS, 0, TRUE);
185--
186GitLab
187
188