diff --git a/backport-Add-lock-in-_g_get_unix_mount_points-around-fsent-functions.patch b/backport-Add-lock-in-_g_get_unix_mount_points-around-fsent-functions.patch new file mode 100644 index 0000000000000000000000000000000000000000..4c52f54fe15388d87f73b11a207c8655a2448fc2 --- /dev/null +++ b/backport-Add-lock-in-_g_get_unix_mount_points-around-fsent-functions.patch @@ -0,0 +1,69 @@ +From f43cf341511dd684a58c09e104e28c11987cbff1 Mon Sep 17 00:00:00 2001 +From: Rozhuk Ivan +Date: Sat, 25 Jun 2022 18:46:08 +0300 +Subject: [PATCH] [PATCH] Add lock in _g_get_unix_mount_points() around + *fsent() functions + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/f43cf341511dd684a58c09e104e28c11987cbff1 + +--- + gio/gunixmounts.c | 22 +++++++++++++--------- + 1 file changed, 13 insertions(+), 9 deletions(-) + +diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c +index 563bdba3b2..3005aa7af3 100644 +--- a/gio/gunixmounts.c ++++ b/gio/gunixmounts.c +@@ -1410,17 +1410,13 @@ _g_get_unix_mount_points (void) + { + struct fstab *fstab = NULL; + GUnixMountPoint *mount_point; +- GList *return_list; ++ GList *return_list = NULL; ++ G_LOCK_DEFINE_STATIC (fsent); + #ifdef HAVE_SYS_SYSCTL_H + int usermnt = 0; + struct stat sb; + #endif +- +- if (!setfsent ()) +- return NULL; + +- return_list = NULL; +- + #ifdef HAVE_SYS_SYSCTL_H + #if defined(HAVE_SYSCTLBYNAME) + { +@@ -1448,7 +1444,14 @@ _g_get_unix_mount_points (void) + } + #endif + #endif +- ++ ++ G_LOCK (fsent); ++ if (!setfsent ()) ++ { ++ G_UNLOCK (fsent); ++ return NULL; ++ } ++ + while ((fstab = getfsent ()) != NULL) + { + gboolean is_read_only = FALSE; +@@ -1482,9 +1485,10 @@ _g_get_unix_mount_points (void) + + return_list = g_list_prepend (return_list, mount_point); + } +- ++ + endfsent (); +- ++ G_UNLOCK (fsent); ++ + return g_list_reverse (return_list); + } + /* Interix {{{2 */ +-- +GitLab + diff --git a/backport-Handling-collision-between-standard-i-o-file-descriptors-and-newly-created-ones.patch b/backport-Handling-collision-between-standard-i-o-file-descriptors-and-newly-created-ones.patch new file mode 100644 index 0000000000000000000000000000000000000000..0dd94f7baf2c0a7e800ec7eb34ca3b99a807b368 --- /dev/null +++ b/backport-Handling-collision-between-standard-i-o-file-descriptors-and-newly-created-ones.patch @@ -0,0 +1,68 @@ +From d9ba6150909818beb05573f54f26232063492c5b Mon Sep 17 00:00:00 2001 +From: Emmanuel Fleury +Date: Mon, 1 Aug 2022 19:05:14 +0200 +Subject: [PATCH] Handling collision between standard i/o file descriptors and + newly created ones + +Though unlikely to happen, it may happen that newly created file +descriptor take the value 0 (stdin), 1 (stdout) or 2 (stderr) if one +of the standard ones have been dismissed in between. So, it may +confuse the program if it is unaware of this change. + +The point of this patch is to avoid a reasign of standard file +descriptors on newly created ones. + +Closes issue #16 + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/d9ba6150909818beb05573f54f26232063492c5b + +--- + glib/glib-unix.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/glib/glib-unix.c b/glib/glib-unix.c +index d2dea10ef0..d67b8a357a 100644 +--- a/glib/glib-unix.c ++++ b/glib/glib-unix.c +@@ -108,6 +108,17 @@ g_unix_open_pipe (int *fds, + ecode = pipe2 (fds, pipe2_flags); + if (ecode == -1 && errno != ENOSYS) + return g_unix_set_error_from_errno (error, errno); ++ /* Don't reassign pipes to stdin, stdout, stderr if closed meanwhile */ ++ else if (fds[0] < 3 || fds[1] < 3) ++ { ++ int old_fds[2] = { fds[0], fds[1] }; ++ gboolean result = g_unix_open_pipe (fds, flags, error); ++ close (old_fds[0]); ++ close (old_fds[1]); ++ ++ if (!result) ++ g_unix_set_error_from_errno (error, errno); ++ } + else if (ecode == 0) + return TRUE; + /* Fall through on -ENOSYS, we must be running on an old kernel */ +@@ -116,6 +127,19 @@ g_unix_open_pipe (int *fds, + ecode = pipe (fds); + if (ecode == -1) + return g_unix_set_error_from_errno (error, errno); ++ /* Don't reassign pipes to stdin, stdout, stderr if closed meanwhile */ ++ else if (fds[0] < 3 || fds[1] < 3) ++ { ++ int old_fds[2] = { fds[0], fds[1] }; ++ gboolean result = g_unix_open_pipe (fds, flags, error); ++ close (old_fds[0]); ++ close (old_fds[1]); ++ ++ if (!result) ++ g_unix_set_error_from_errno (error, errno); ++ ++ return result; ++ } + + if (flags == 0) + return TRUE; +-- +GitLab + diff --git a/backport-Implement-GFileIface.set_display_name-for-resource-files.patch b/backport-Implement-GFileIface.set_display_name-for-resource-files.patch new file mode 100644 index 0000000000000000000000000000000000000000..ca4f5577656f2d42571476749a50ba5a3811439b --- /dev/null +++ b/backport-Implement-GFileIface.set_display_name-for-resource-files.patch @@ -0,0 +1,52 @@ +From a9394bd68e222377f0156bf9c213b3f3a1e340d0 Mon Sep 17 00:00:00 2001 +From: Emmanuele Bassi +Date: Sat, 30 Jul 2022 20:03:42 +0100 +Subject: [PATCH] Implement GFileIface.set_display_name() for resource files + +Resource files cannot be renamed, and GFileIface.set_display_name() is +mandatory. + +Fixes: #2705 + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/a9394bd68e222377f0156bf9c213b3f3a1e340d0 + +--- + gio/gresourcefile.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/gio/gresourcefile.c b/gio/gresourcefile.c +index 340d3378b3..24f20f2903 100644 +--- a/gio/gresourcefile.c ++++ b/gio/gresourcefile.c +@@ -646,6 +646,19 @@ g_resource_file_monitor_file (GFile *file, + return g_object_new (g_resource_file_monitor_get_type (), NULL); + } + ++static GFile * ++g_resource_file_set_display_name (GFile *file, ++ const char *display_name, ++ GCancellable *cancellable, ++ GError **error) ++{ ++ g_set_error_literal (error, ++ G_IO_ERROR, ++ G_IO_ERROR_NOT_SUPPORTED, ++ _("Resource files cannot be renamed")); ++ return NULL; ++} ++ + static void + g_resource_file_file_iface_init (GFileIface *iface) + { +@@ -664,6 +677,7 @@ g_resource_file_file_iface_init (GFileIface *iface) + iface->get_relative_path = g_resource_file_get_relative_path; + iface->resolve_relative_path = g_resource_file_resolve_relative_path; + iface->get_child_for_display_name = g_resource_file_get_child_for_display_name; ++ iface->set_display_name = g_resource_file_set_display_name; + iface->enumerate_children = g_resource_file_enumerate_children; + iface->query_info = g_resource_file_query_info; + iface->query_filesystem_info = g_resource_file_query_filesystem_info; +-- +GitLab + diff --git a/backport-documentportal-Fix-small-leak-in-add_documents-with-empty-URI-list.patch b/backport-documentportal-Fix-small-leak-in-add_documents-with-empty-URI-list.patch new file mode 100644 index 0000000000000000000000000000000000000000..b0f8a1d1685df31bd7238123064efa021b90601b --- /dev/null +++ b/backport-documentportal-Fix-small-leak-in-add_documents-with-empty-URI-list.patch @@ -0,0 +1,34 @@ +From 27203e48c91ab8b55033dcf1773cb60c0aaed3fa Mon Sep 17 00:00:00 2001 +From: Sebastian Keller +Date: Tue, 30 Aug 2022 21:39:36 +0200 +Subject: [PATCH] documentportal: Fix small leak in add_documents with empty + URI list + +When called with an empty URI list (or only inaccessible files), +g_document_portal_add_documents would not call g_variant_builder_end, +leaking the memory allocated by the variant builder. + +Closes: https://gitlab.gnome.org/GNOME/glib/-/issues/2733 + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/27203e48c91ab8b55033dcf1773cb60c0aaed3fa + +--- + gio/gdocumentportal.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/gio/gdocumentportal.c b/gio/gdocumentportal.c +index c08c36c581..382e2aab6e 100644 +--- a/gio/gdocumentportal.c ++++ b/gio/gdocumentportal.c +@@ -203,6 +203,7 @@ g_document_portal_add_documents (GList *uris, + else + { + ruris = g_list_copy_deep (uris, (GCopyFunc)g_strdup, NULL); ++ g_variant_builder_clear (&builder); + } + + out: +-- +GitLab + diff --git a/backport-g_get_unix_mount_points-reduce-syscalls-inside-loop.patch b/backport-g_get_unix_mount_points-reduce-syscalls-inside-loop.patch new file mode 100644 index 0000000000000000000000000000000000000000..2c8c7f3a3a33362c1900d72f2d9412f86c4d3af5 --- /dev/null +++ b/backport-g_get_unix_mount_points-reduce-syscalls-inside-loop.patch @@ -0,0 +1,46 @@ +From 02d0d6497b92d05d1145d1077654ad2453938b6c Mon Sep 17 00:00:00 2001 +From: Rozhuk Ivan +Date: Sat, 25 Jun 2022 19:01:30 +0300 +Subject: [PATCH] [PATCH] _g_get_unix_mount_points(): reduce syscalls inside + loop + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/02d0d6497b92d05d1145d1077654ad2453938b6c + +--- + gio/gunixmounts.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) +diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c +index ba08245..92ab163 100644 +--- a/gio/gunixmounts.c ++++ b/gio/gunixmounts.c +@@ -1414,6 +1414,7 @@ _g_get_unix_mount_points (void) + GList *return_list = NULL; + G_LOCK_DEFINE_STATIC (fsent); + #ifdef HAVE_SYS_SYSCTL_H ++ uid_t uid = getuid (); + int usermnt = 0; + struct stat sb; + #endif +@@ -1466,14 +1467,13 @@ _g_get_unix_mount_points (void) + + #ifdef HAVE_SYS_SYSCTL_H + if (usermnt != 0) +- { +- uid_t uid = getuid (); +- if (stat (fstab->fs_file, &sb) == 0) +- { +- if (uid == 0 || sb.st_uid == uid) +- is_user_mountable = TRUE; +- } +- } ++ { ++ if (uid == 0 || ++ (stat (fstab->fs_file, &sb) == 0 && sb.st_uid == uid)) ++ { ++ is_user_mountable = TRUE; ++ } ++ } + #endif + + mount_point = create_unix_mount_point (fstab->fs_spec, diff --git a/backport-gdesktopappinfo-Unref-the-GDBus-call-results.patch b/backport-gdesktopappinfo-Unref-the-GDBus-call-results.patch new file mode 100644 index 0000000000000000000000000000000000000000..0d5d1d3324901d6f92ad611861e8ba7939a0442e --- /dev/null +++ b/backport-gdesktopappinfo-Unref-the-GDBus-call-results.patch @@ -0,0 +1,48 @@ +From 221f22b6e18fdd306e676e28a79afd3697bddd03 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 2 Sep 2022 20:38:46 +0200 +Subject: [PATCH] gdesktopappinfo: Unref the GDBus call results + +On our GDBus call callback wrapper we were completing the gdbus call but +ignoring the returned value, that was always leaked. + +Fix this. + +Helps with: https://gitlab.gnome.org/GNOME/glib/-/issues/333 + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/221f22b6e18fdd306e676e28a79afd3697bddd03 + +--- + gio/gdesktopappinfo.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c +index af2311ca52..52d308f540 100644 +--- a/gio/gdesktopappinfo.c ++++ b/gio/gdesktopappinfo.c +@@ -3283,15 +3283,19 @@ launch_uris_with_dbus_cb (GObject *object, + { + GTask *task = G_TASK (user_data); + GError *error = NULL; ++ GVariant *ret; + +- g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error); ++ ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error); + if (error != NULL) + { + g_dbus_error_strip_remote_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + } + else +- g_task_return_boolean (task, TRUE); ++ { ++ g_task_return_boolean (task, TRUE); ++ g_variant_unref (ret); ++ } + + g_object_unref (task); + } +-- +GitLab + diff --git a/backport-gio-tests-gdbus-peer-Unref-cached-property-GVariant-value.patch b/backport-gio-tests-gdbus-peer-Unref-cached-property-GVariant-value.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a62b5b1cd67aef3ab8b1e96295cd368e6d1317d --- /dev/null +++ b/backport-gio-tests-gdbus-peer-Unref-cached-property-GVariant-value.patch @@ -0,0 +1,29 @@ +From e268ff39b648e7b100d2aa50f472b4ff8ff5313a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 2 Sep 2022 21:10:05 +0200 +Subject: [PATCH] gio/tests/gdbus-peer: Unref cached property GVariant value + +Helps with: https://gitlab.gnome.org/GNOME/glib/-/issues/333 + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/e268ff39b648e7b100d2aa50f472b4ff8ff5313a + +--- + gio/tests/gdbus-peer.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/gio/tests/gdbus-peer.c b/gio/tests/gdbus-peer.c +index 7179d089df..763689a4fd 100644 +--- a/gio/tests/gdbus-peer.c ++++ b/gio/tests/gdbus-peer.c +@@ -843,6 +843,7 @@ do_test_peer (void) + error = NULL; + value = g_dbus_proxy_get_cached_property (proxy, "PeerProperty"); + g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "ThePropertyValue"); ++ g_clear_pointer (&value, g_variant_unref); + + /* try invoking a method */ + error = NULL; +-- +GitLab + diff --git a/backport-gio-tests-gdbus-proxy-threads-Unref-GVariant-s-that-we-own.patch b/backport-gio-tests-gdbus-proxy-threads-Unref-GVariant-s-that-we-own.patch new file mode 100644 index 0000000000000000000000000000000000000000..ce5f46b5fbd4d662c5f1d2212d0152a5109e6595 --- /dev/null +++ b/backport-gio-tests-gdbus-proxy-threads-Unref-GVariant-s-that-we-own.patch @@ -0,0 +1,67 @@ +From 1da208cddc19cad05ccf4b798a99f7045e41ffc4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 2 Sep 2022 20:26:06 +0200 +Subject: [PATCH] gio/tests/gdbus-proxy-threads: Unref GVariant's that we own + +This test is leaking various GVariant's that we are supposed to unref, +leading the valgrind CI job to complain about. + +Helps with: https://gitlab.gnome.org/GNOME/glib/-/issues/333 + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/1da208cddc19cad05ccf4b798a99f7045e41ffc4 + +--- + gio/tests/gdbus-proxy-threads.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/gio/tests/gdbus-proxy-threads.c b/gio/tests/gdbus-proxy-threads.c +index 76b857e731..a0a38d07cd 100644 +--- a/gio/tests/gdbus-proxy-threads.c ++++ b/gio/tests/gdbus-proxy-threads.c +@@ -119,13 +119,17 @@ request_name_cb (GObject *source, + GDBusConnection *connection = G_DBUS_CONNECTION (source); + GError *error = NULL; + GVariant *var; ++ GVariant *child; + + var = g_dbus_connection_call_finish (connection, res, &error); + g_assert_no_error (error); +- g_assert_cmpuint (g_variant_get_uint32 (g_variant_get_child_value (var, 0)), ++ child = g_variant_get_child_value (var, 0); ++ g_assert_cmpuint (g_variant_get_uint32 (child), + ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); + + release_name (connection, TRUE); ++ g_variant_unref (child); ++ g_variant_unref (var); + } + + static void +@@ -154,11 +158,13 @@ release_name_cb (GObject *source, + GDBusConnection *connection = G_DBUS_CONNECTION (source); + GError *error = NULL; + GVariant *var; ++ GVariant *child; + int i; + + var = g_dbus_connection_call_finish (connection, res, &error); + g_assert_no_error (error); +- g_assert_cmpuint (g_variant_get_uint32 (g_variant_get_child_value (var, 0)), ++ child = g_variant_get_child_value (var, 0); ++ g_assert_cmpuint (g_variant_get_uint32 (child), + ==, DBUS_RELEASE_NAME_REPLY_RELEASED); + + /* generate some rapid NameOwnerChanged signals to try to trigger crashes */ +@@ -170,6 +176,8 @@ release_name_cb (GObject *source, + + /* wait for dbus-daemon to catch up */ + request_name (connection, TRUE); ++ g_variant_unref (child); ++ g_variant_unref (var); + } + + static void +-- +GitLab + diff --git a/backport-glocalfileoutputstream-Do-not-double-close-an-fd-on-unlink-error.patch b/backport-glocalfileoutputstream-Do-not-double-close-an-fd-on-unlink-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..39228fc64c27b1a0811d5b3bf44ef3a85a51bf8b --- /dev/null +++ b/backport-glocalfileoutputstream-Do-not-double-close-an-fd-on-unlink-error.patch @@ -0,0 +1,33 @@ +From 2401e1a090dcaac7614a8984cd3e3832a2a476ab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 16 Sep 2022 15:11:47 +0200 +Subject: [PATCH] glocalfileoutputstream: Do not double-close an fd on unlink + error + +In case we fail unlinking a file we could close again an FD that has +been already just closed. So avoid this by unsetting it when closing. + +Coverity CID: #1474462 + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/2401e1a090dcaac7614a8984cd3e3832a2a476ab + +--- + gio/glocalfileoutputstream.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c +index 78d3e85..a61d5b5 100644 +--- a/gio/glocalfileoutputstream.c ++++ b/gio/glocalfileoutputstream.c +@@ -1163,6 +1163,7 @@ handle_overwrite_open (const char *filename, + if (replace_destination_set) + { + g_close (fd, NULL); ++ fd = -1; + + if (g_unlink (filename) != 0) + { +-- +2.33.0 + diff --git a/backport-gregex-Avoid-re-allocating-if-we-have-no-size-change.patch b/backport-gregex-Avoid-re-allocating-if-we-have-no-size-change.patch new file mode 100644 index 0000000000000000000000000000000000000000..0164d75b8ee401d039d05161d323d1963f59e784 --- /dev/null +++ b/backport-gregex-Avoid-re-allocating-if-we-have-no-size-change.patch @@ -0,0 +1,47 @@ +From aee84cb45caf42e336dee5183d561b89eb44f8f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 18:56:39 +0200 +Subject: [PATCH] gregex: Avoid re-allocating if we have no size change + +This is handled by the syscall underneath, but we can just avoid a call +cheaply. +--- + glib/gregex.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/glib/gregex.c b/glib/gregex.c +index 84c4245753..cf86f0fe0d 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -832,6 +832,7 @@ recalc_match_offsets (GMatchInfo *match_info, + GError **error) + { + PCRE2_SIZE *ovector; ++ uint32_t pre_n_offset; + uint32_t i; + + if (pcre2_get_ovector_count (match_info->match_data) > G_MAXUINT32 / 2) +@@ -842,11 +843,17 @@ recalc_match_offsets (GMatchInfo *match_info, + return FALSE; + } + ++ pre_n_offset = match_info->n_offsets; + match_info->n_offsets = pcre2_get_ovector_count (match_info->match_data) * 2; + ovector = pcre2_get_ovector_pointer (match_info->match_data); +- match_info->offsets = g_realloc_n (match_info->offsets, +- match_info->n_offsets, +- sizeof (gint)); ++ ++ if (match_info->n_offsets != pre_n_offset) ++ { ++ match_info->offsets = g_realloc_n (match_info->offsets, ++ match_info->n_offsets, ++ sizeof (gint)); ++ } ++ + for (i = 0; i < match_info->n_offsets; i++) + { + match_info->offsets[i] = (int) ovector[i]; +-- +GitLab + diff --git a/backport-gregex-Do-not-try-access-the-undefined-match-offsets.patch b/backport-gregex-Do-not-try-access-the-undefined-match-offsets.patch new file mode 100644 index 0000000000000000000000000000000000000000..fbc510f6a83ababeea00fe1ba6747fa39b7fb58b --- /dev/null +++ b/backport-gregex-Do-not-try-access-the-undefined-match-offsets.patch @@ -0,0 +1,56 @@ +From 1f88976610d5bcc15ad58c9345848d736d64fd55 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 17:16:07 +0200 +Subject: [PATCH] gregex: Do not try access the undefined match offsets if we + have no match + +In case we're getting NO-MATCH "errors", we were still recomputing the +match offsets and taking decisions based on that, that might lead to +undefined behavior. + +Avoid this by just returning early a FALSE result (but with no error) in +case there's no result to proceed on. + +Fixes: #2741 +--- + glib/gregex.c | 6 ++++++ + glib/tests/regex.c | 6 ++++++ + 2 files changed, 12 insertions(+) + +diff --git a/glib/gregex.c b/glib/gregex.c +index 219d9cee34..f2a5b5fd1c 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -1073,6 +1073,12 @@ g_match_info_next (GMatchInfo *match_info, + match_info->regex->pattern, match_error (match_info->matches)); + return FALSE; + } ++ else if (match_info->matches == PCRE2_ERROR_NOMATCH) ++ { ++ /* We're done with this match info */ ++ match_info->pos = -1; ++ return FALSE; ++ } + else + if (!recalc_match_offsets (match_info, error)) + return FALSE; +diff --git a/glib/tests/regex.c b/glib/tests/regex.c +index 10daa7814a..291c21b4c7 100644 +--- a/glib/tests/regex.c ++++ b/glib/tests/regex.c +@@ -1669,6 +1669,12 @@ test_class (void) + res = g_match_info_next (match, NULL); + g_assert (!res); + ++ /* Accessing match again should not crash */ ++ g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, ++ "*match_info->pos >= 0*"); ++ g_assert_false (g_match_info_next (match, NULL)); ++ g_test_assert_expected_messages (); ++ + g_match_info_free (match); + g_regex_unref (regex); + } +-- +GitLab + diff --git a/backport-gregex-Fix-a-potential-PCRE2-code-leak-on-reallocation-failures.patch b/backport-gregex-Fix-a-potential-PCRE2-code-leak-on-reallocation-failures.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1dd7801acf3ae30ae6998eb6708d31ef8a3d5b0 --- /dev/null +++ b/backport-gregex-Fix-a-potential-PCRE2-code-leak-on-reallocation-failures.patch @@ -0,0 +1,50 @@ +From 13ad4296ea8ba66f5620288b2fd06315852e73ae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 17:20:45 +0200 +Subject: [PATCH] gregex: Fix a potential PCRE2 code leak on reallocation + failures + +In case recalc_match_offsets() failed we were just returning, but in +such case, per the documentation we should still set the match_info (if +provided) and free the pcre2 code instance. + +So let's just break the loop we're in it, as if we we've no matches set. +This also avoids re-allocating the offsets array and potentially +accessing to unset data. +--- + glib/gregex.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/glib/gregex.c b/glib/gregex.c +index f2a5b5fd1c..6f3ee88122 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -2337,13 +2337,6 @@ g_regex_match_all_full (const GRegex *regex, + info->match_data, + info->match_context, + info->workspace, info->n_workspace); +- +- if (!recalc_match_offsets (info, error)) +- { +- g_match_info_free (info); +- return FALSE; +- } +- + if (info->matches == PCRE2_ERROR_DFA_WSSIZE) + { + /* info->workspace is too small. */ +@@ -2370,6 +2363,11 @@ g_regex_match_all_full (const GRegex *regex, + _("Error while matching regular expression %s: %s"), + regex->pattern, match_error (info->matches)); + } ++ else if (info->matches > 0) ++ { ++ if (!recalc_match_offsets (info, error)) ++ info->matches = PCRE2_ERROR_NOMATCH; ++ } + } + + pcre2_code_free (pcre_re); +-- +GitLab + diff --git a/backport-gregex-Handle-the-case-we-need-to-re-allocate-the-match-data.patch b/backport-gregex-Handle-the-case-we-need-to-re-allocate-the-match-data.patch new file mode 100644 index 0000000000000000000000000000000000000000..f9d340ea8d6b3d842aa734b2b835641d6be0eb1f --- /dev/null +++ b/backport-gregex-Handle-the-case-we-need-to-re-allocate-the-match-data.patch @@ -0,0 +1,51 @@ +From 11521972f4d345d9a3f68df719f5980085197e47 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 18:26:12 +0200 +Subject: [PATCH] gregex: Handle the case we need to re-allocate the match data + +In case PCRE2 returns an empty match + +This can be easily tested by initializing the initial match data to a +value that is less than the expected match values (e.g. by calling +pcre2_match_data_create (1, NULL)), but we can't do it in our tests +without bigger changes. +--- + glib/gregex.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/glib/gregex.c b/glib/gregex.c +index b886b24e2a..84c4245753 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -1027,7 +1027,7 @@ g_match_info_next (GMatchInfo *match_info, + { + gint prev_match_start; + gint prev_match_end; +- gint opts; ++ uint32_t opts; + + g_return_val_if_fail (match_info != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); +@@ -1075,6 +1075,19 @@ g_match_info_next (GMatchInfo *match_info, + match_info->regex->pattern, match_error (match_info->matches)); + return FALSE; + } ++ else if (match_info->matches == 0) ++ { ++ /* info->offsets is too small. */ ++ match_info->n_offsets *= 2; ++ match_info->offsets = g_realloc_n (match_info->offsets, ++ match_info->n_offsets, ++ sizeof (gint)); ++ ++ pcre2_match_data_free (match_info->match_data); ++ match_info->match_data = pcre2_match_data_create (match_info->n_offsets, NULL); ++ ++ return g_match_info_next (match_info, error); ++ } + else if (match_info->matches == PCRE2_ERROR_NOMATCH) + { + /* We're done with this match info */ +-- +GitLab + diff --git a/backport-gregex-Mark-g_match_info_get_regex-as-transfer-none.patch b/backport-gregex-Mark-g_match_info_get_regex-as-transfer-none.patch new file mode 100644 index 0000000000000000000000000000000000000000..f0e86e93b19f1e3aebe36e348220f68a0a25dd3d --- /dev/null +++ b/backport-gregex-Mark-g_match_info_get_regex-as-transfer-none.patch @@ -0,0 +1,27 @@ +From 1185a1304a88319b58359105f2c1038ae4d7edce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 16:46:13 +0200 +Subject: [PATCH] gregex: Mark g_match_info_get_regex as transfer none + +Since it had no explicit annotation, g-i was defaulting to transfer-full +while in this case the GRegex is owned by the GMatchInfo. +--- + glib/gregex.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/glib/gregex.c b/glib/gregex.c +index 2eb9b858ea..219d9cee34 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -912,7 +912,7 @@ enable_jit_with_match_options (GRegex *regex, + * and must not be freed. Use g_regex_ref() if you need to keep it + * after you free @match_info object. + * +- * Returns: #GRegex object used in @match_info ++ * Returns: (transfer none): #GRegex object used in @match_info + * + * Since: 2.14 + */ +-- +GitLab + diff --git a/backport-gsocketclient-Fix-still-reachable-references-to-cancellables.patch b/backport-gsocketclient-Fix-still-reachable-references-to-cancellables.patch new file mode 100644 index 0000000000000000000000000000000000000000..d865a121b8decf9955c98ff2860dfb3b53acf764 --- /dev/null +++ b/backport-gsocketclient-Fix-still-reachable-references-to-cancellables.patch @@ -0,0 +1,117 @@ +From 56d371942e43c52bc6131067e2dc2a35f6cd5a3d Mon Sep 17 00:00:00 2001 +From: Philip Withnall +Date: Mon, 13 Jun 2022 13:06:06 +0100 +Subject: [PATCH] gsocketclient: Fix still-reachable references to cancellables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +`GSocketClient` chains its internal `GCancellable` objects to ones +provided by the caller in two places using `g_cancellable_connect()`. +However, it never calls `g_cancellable_disconnect()`, instead relying +(incorrectly) on the `GCancellable` provided by the caller being +short-lived. + +In the (valid) situation where a caller reuses one `GCancellable` for +multiple socket client calls, or for calls across multiple socket +clients, this will cause the internal `GCancellable` objects from those +`GSocketClient`s to accumulate, with one reference left each (which is +the reference from the `g_cancellable_connect()` closure). + +These `GCancellable` instances aren't technically leaked, as they will +all be freed when the caller's `GCancellable` is disposed, but they are +no longer useful and there is no bound on the number of them which will +hang around. + +For a program doing a lot of socket operations, this still-reachable +memory usage can become significant. + +Fix the problem by adding paired `g_cancellable_disconnect()` calls. +It's not possible to add a unit test as we can't measure still-reachable +memory growth before the end of a unit test when everything has to be +freed. + +Signed-off-by: Philip Withnall + +Fixes: #2670 + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/56d371942e43c52bc6131067e2dc2a35f6cd5a3d + +--- + gio/gsocketclient.c | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c +index ae80f5203c..127915b722 100644 +--- a/gio/gsocketclient.c ++++ b/gio/gsocketclient.c +@@ -1466,6 +1466,8 @@ typedef struct + GSocketConnectable *connectable; + GSocketAddressEnumerator *enumerator; + GCancellable *enumeration_cancellable; ++ GCancellable *enumeration_parent_cancellable; /* (nullable) (owned) */ ++ gulong enumeration_cancelled_id; + + GSList *connection_attempts; + GSList *successful_connections; +@@ -1485,7 +1487,12 @@ g_socket_client_async_connect_data_free (GSocketClientAsyncConnectData *data) + data->task = NULL; + g_clear_object (&data->connectable); + g_clear_object (&data->enumerator); ++ ++ g_cancellable_disconnect (data->enumeration_parent_cancellable, data->enumeration_cancelled_id); ++ g_clear_object (&data->enumeration_parent_cancellable); ++ data->enumeration_cancelled_id = 0; + g_clear_object (&data->enumeration_cancellable); ++ + g_slist_free_full (data->connection_attempts, connection_attempt_unref); + g_slist_free_full (data->successful_connections, connection_attempt_unref); + +@@ -1503,6 +1510,7 @@ typedef struct + GSocketClientAsyncConnectData *data; /* unowned */ + GSource *timeout_source; + GCancellable *cancellable; ++ gulong cancelled_id; + grefcount ref; + } ConnectionAttempt; + +@@ -1530,6 +1538,8 @@ connection_attempt_unref (gpointer pointer) + g_clear_object (&attempt->address); + g_clear_object (&attempt->socket); + g_clear_object (&attempt->connection); ++ g_cancellable_disconnect (g_task_get_cancellable (attempt->data->task), attempt->cancelled_id); ++ attempt->cancelled_id = 0; + g_clear_object (&attempt->cancellable); + g_clear_object (&attempt->proxy_addr); + if (attempt->timeout_source) +@@ -2023,8 +2033,9 @@ g_socket_client_enumerator_callback (GObject *object, + data->connection_attempts = g_slist_append (data->connection_attempts, attempt); + + if (g_task_get_cancellable (data->task)) +- g_cancellable_connect (g_task_get_cancellable (data->task), G_CALLBACK (on_connection_cancelled), +- g_object_ref (attempt->cancellable), g_object_unref); ++ attempt->cancelled_id = ++ g_cancellable_connect (g_task_get_cancellable (data->task), G_CALLBACK (on_connection_cancelled), ++ g_object_ref (attempt->cancellable), g_object_unref); + + g_socket_connection_set_cached_remote_address ((GSocketConnection *)attempt->connection, address); + g_debug ("GSocketClient: Starting TCP connection attempt"); +@@ -2129,8 +2140,12 @@ g_socket_client_connect_async (GSocketClient *client, + + data->enumeration_cancellable = g_cancellable_new (); + if (cancellable) +- g_cancellable_connect (cancellable, G_CALLBACK (on_connection_cancelled), +- g_object_ref (data->enumeration_cancellable), g_object_unref); ++ { ++ data->enumeration_parent_cancellable = g_object_ref (cancellable); ++ data->enumeration_cancelled_id = ++ g_cancellable_connect (cancellable, G_CALLBACK (on_connection_cancelled), ++ g_object_ref (data->enumeration_cancellable), g_object_unref); ++ } + + enumerator_next_async (data, FALSE); + } +-- +GitLab + diff --git a/backport-regex-Actually-check-for-match-options-changes.patch b/backport-regex-Actually-check-for-match-options-changes.patch new file mode 100644 index 0000000000000000000000000000000000000000..a87c890e419fc889726516e8ecde76b4be0eb730 --- /dev/null +++ b/backport-regex-Actually-check-for-match-options-changes.patch @@ -0,0 +1,25 @@ +From d4966911e6b35d8923bc6cd58e7cb8a1b0e09d4a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 21:44:12 +0200 +Subject: [PATCH] tests/regex: Actually check for match options changes + +--- + glib/tests/regex.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/glib/tests/regex.c b/glib/tests/regex.c +index 567b6e2202..abf27e619e 100644 +--- a/glib/tests/regex.c ++++ b/glib/tests/regex.c +@@ -105,7 +105,7 @@ test_new (gconstpointer d) + data = g_new0 (TestNewData, 1); \ + data->pattern = _pattern; \ + data->compile_opts = _compile_opts; \ +- data->match_opts = 0; \ ++ data->match_opts = _match_opts; \ + data->expected_error = 0; \ + data->check_flags = TRUE; \ + data->real_compile_opts = _real_compile_opts; \ +-- +GitLab + diff --git a/backport-regex-Add-debug-strings-for-compile-and-match-option-flags.patch b/backport-regex-Add-debug-strings-for-compile-and-match-option-flags.patch new file mode 100644 index 0000000000000000000000000000000000000000..c8ddc8ba3db1418f4975541250c3a3f1b9414ed5 --- /dev/null +++ b/backport-regex-Add-debug-strings-for-compile-and-match-option-flags.patch @@ -0,0 +1,193 @@ +From 23c1b401d8c78c2c66d55b94d7d833210d518853 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 14:21:27 +0200 +Subject: [PATCH] tests/regex: Add debug strings for compile and match option + flags + +In case of failures they give a better info. +--- + glib/tests/regex.c | 132 +++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 122 insertions(+), 10 deletions(-) + +diff --git a/glib/tests/regex.c b/glib/tests/regex.c +index acb082b704..567b6e2202 100644 +--- a/glib/tests/regex.c ++++ b/glib/tests/regex.c +@@ -184,6 +184,108 @@ test_match_simple (gconstpointer d) + #define TEST_MATCH_NOTEMPTY_ATSTART(_pattern, _string, _expected) \ + TEST_MATCH_SIMPLE_NAMED("notempty-atstart", _pattern, _string, 0, G_REGEX_MATCH_NOTEMPTY_ATSTART, _expected) + ++static char * ++compile_options_to_string (GRegexCompileFlags compile_flags) ++{ ++ GStrvBuilder *builder = g_strv_builder_new(); ++ GStrv strv; ++ char *ret; ++ ++ if (compile_flags & G_REGEX_DEFAULT) ++ g_strv_builder_add (builder, "default"); ++ if (compile_flags & G_REGEX_CASELESS) ++ g_strv_builder_add (builder, "caseless"); ++ if (compile_flags & G_REGEX_MULTILINE) ++ g_strv_builder_add (builder, "multiline"); ++ if (compile_flags & G_REGEX_DOTALL) ++ g_strv_builder_add (builder, "dotall"); ++ if (compile_flags & G_REGEX_EXTENDED) ++ g_strv_builder_add (builder, "extended"); ++ if (compile_flags & G_REGEX_ANCHORED) ++ g_strv_builder_add (builder, "anchored"); ++ if (compile_flags & G_REGEX_DOLLAR_ENDONLY) ++ g_strv_builder_add (builder, "dollar-endonly"); ++ if (compile_flags & G_REGEX_UNGREEDY) ++ g_strv_builder_add (builder, "ungreedy"); ++ if (compile_flags & G_REGEX_RAW) ++ g_strv_builder_add (builder, "raw"); ++ if (compile_flags & G_REGEX_NO_AUTO_CAPTURE) ++ g_strv_builder_add (builder, "no-auto-capture"); ++ if (compile_flags & G_REGEX_OPTIMIZE) ++ g_strv_builder_add (builder, "optimize"); ++ if (compile_flags & G_REGEX_FIRSTLINE) ++ g_strv_builder_add (builder, "firstline"); ++ if (compile_flags & G_REGEX_DUPNAMES) ++ g_strv_builder_add (builder, "dupnames"); ++ if (compile_flags & G_REGEX_NEWLINE_CR) ++ g_strv_builder_add (builder, "newline-cr"); ++ if (compile_flags & G_REGEX_NEWLINE_LF) ++ g_strv_builder_add (builder, "newline-lf"); ++ if (compile_flags & G_REGEX_NEWLINE_CRLF) ++ g_strv_builder_add (builder, "newline-crlf"); ++ if (compile_flags & G_REGEX_NEWLINE_ANYCRLF) ++ g_strv_builder_add (builder, "newline-anycrlf"); ++ if (compile_flags & G_REGEX_BSR_ANYCRLF) ++ g_strv_builder_add (builder, "bsr-anycrlf"); ++ ++ strv = g_strv_builder_end (builder); ++ ret = g_strjoinv ("|", strv); ++ ++ g_strfreev (strv); ++ g_strv_builder_unref (builder); ++ ++ return ret; ++} ++ ++static char * ++match_options_to_string (GRegexMatchFlags match_flags) ++{ ++ GStrvBuilder *builder = g_strv_builder_new(); ++ GStrv strv; ++ char *ret; ++ ++ if (match_flags & G_REGEX_MATCH_DEFAULT) ++ g_strv_builder_add (builder, "default"); ++ if (match_flags & G_REGEX_MATCH_ANCHORED) ++ g_strv_builder_add (builder, "anchored"); ++ if (match_flags & G_REGEX_MATCH_NOTBOL) ++ g_strv_builder_add (builder, "notbol"); ++ if (match_flags & G_REGEX_MATCH_NOTEOL) ++ g_strv_builder_add (builder, "noteol"); ++ if (match_flags & G_REGEX_MATCH_NOTEMPTY) ++ g_strv_builder_add (builder, "notempty"); ++ if (match_flags & G_REGEX_MATCH_PARTIAL) ++ g_strv_builder_add (builder, "partial"); ++ if (match_flags & G_REGEX_MATCH_NEWLINE_CR) ++ g_strv_builder_add (builder, "newline-cr"); ++ if (match_flags & G_REGEX_MATCH_NEWLINE_LF) ++ g_strv_builder_add (builder, "newline-lf"); ++ if (match_flags & G_REGEX_MATCH_NEWLINE_CRLF) ++ g_strv_builder_add (builder, "newline-crlf"); ++ if (match_flags & G_REGEX_MATCH_NEWLINE_ANY) ++ g_strv_builder_add (builder, "newline-any"); ++ if (match_flags & G_REGEX_MATCH_NEWLINE_ANYCRLF) ++ g_strv_builder_add (builder, "newline-anycrlf"); ++ if (match_flags & G_REGEX_MATCH_BSR_ANYCRLF) ++ g_strv_builder_add (builder, "bsr-anycrlf"); ++ if (match_flags & G_REGEX_MATCH_BSR_ANY) ++ g_strv_builder_add (builder, "bsr-any"); ++ if (match_flags & G_REGEX_MATCH_PARTIAL_SOFT) ++ g_strv_builder_add (builder, "partial-soft"); ++ if (match_flags & G_REGEX_MATCH_PARTIAL_HARD) ++ g_strv_builder_add (builder, "partial-hard"); ++ if (match_flags & G_REGEX_MATCH_NOTEMPTY_ATSTART) ++ g_strv_builder_add (builder, "notempty-atstart"); ++ ++ strv = g_strv_builder_end (builder); ++ ret = g_strjoinv ("|", strv); ++ ++ g_strfreev (strv); ++ g_strv_builder_unref (builder); ++ ++ return ret; ++} ++ + static void + test_match (gconstpointer d) + { +@@ -191,6 +293,9 @@ test_match (gconstpointer d) + GRegex *regex; + gboolean match; + GError *error = NULL; ++ gchar *compile_opts_str; ++ gchar *match_opts_str; ++ gchar *match_opts2_str; + + regex = g_regex_new (data->pattern, data->compile_opts, data->match_opts, &error); + g_assert (regex != NULL); +@@ -199,31 +304,35 @@ test_match (gconstpointer d) + match = g_regex_match_full (regex, data->string, data->string_len, + data->start_position, data->match_opts2, NULL, NULL); + ++ compile_opts_str = compile_options_to_string (data->compile_opts); ++ match_opts_str = match_options_to_string (data->match_opts); ++ match_opts2_str = match_options_to_string (data->match_opts2); ++ + if (data->expected) + { + if (!match) +- g_error ("Regex '%s' (with compile options %u and " +- "match options %u) should have matched '%.*s' " +- "(of length %d, at position %d, with match options %u) but did not", +- data->pattern, data->compile_opts, data->match_opts, ++ g_error ("Regex '%s' (with compile options '%s' and " ++ "match options '%s') should have matched '%.*s' " ++ "(of length %d, at position %d, with match options '%s') but did not", ++ data->pattern, compile_opts_str, match_opts_str, + data->string_len == -1 ? (int) strlen (data->string) : + (int) data->string_len, + data->string, (int) data->string_len, +- data->start_position, data->match_opts2); ++ data->start_position, match_opts2_str); + + g_assert_cmpint (match, ==, TRUE); + } + else + { + if (match) +- g_error ("Regex '%s' (with compile options %u and " +- "match options %u) should not have matched '%.*s' " +- "(of length %d, at position %d, with match options %u) but did", +- data->pattern, data->compile_opts, data->match_opts, ++ g_error ("Regex '%s' (with compile options '%s' and " ++ "match options '%s') should not have matched '%.*s' " ++ "(of length %d, at position %d, with match options '%s') but did", ++ data->pattern, compile_opts_str, match_opts_str, + data->string_len == -1 ? (int) strlen (data->string) : + (int) data->string_len, + data->string, (int) data->string_len, +- data->start_position, data->match_opts2); ++ data->start_position, match_opts2_str); + } + + if (data->string_len == -1 && data->start_position == 0) +@@ -232,6 +341,9 @@ test_match (gconstpointer d) + g_assert_cmpint (match, ==, data->expected); + } + ++ g_free (compile_opts_str); ++ g_free (match_opts_str); ++ g_free (match_opts2_str); + g_regex_unref (regex); + } + +-- +GitLab + diff --git a/backport-regex-Add-test-for-gtksourceview-regression.patch b/backport-regex-Add-test-for-gtksourceview-regression.patch new file mode 100644 index 0000000000000000000000000000000000000000..b109dfebf0731f10680feac0649d17f60a75456a --- /dev/null +++ b/backport-regex-Add-test-for-gtksourceview-regression.patch @@ -0,0 +1,33 @@ +From df66951b96fdb800c0b6bd11292bb23fbcd6ed85 Mon Sep 17 00:00:00 2001 +From: Aleksei Rybalkin +Date: Thu, 1 Sep 2022 18:19:11 +0200 +Subject: [PATCH] tests/regex: Add test for gtksourceview regression + +--- + glib/tests/regex.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/glib/tests/regex.c b/glib/tests/regex.c +index ce946d0592..10daa7814a 100644 +--- a/glib/tests/regex.c ++++ b/glib/tests/regex.c +@@ -2434,6 +2434,16 @@ main (int argc, char *argv[]) + TEST_NEW_FAIL ("\\k", 0, G_REGEX_ERROR_MISSING_NAME); + TEST_NEW_FAIL ("a[\\NB]c", 0, G_REGEX_ERROR_NOT_SUPPORTED_IN_CLASS); + TEST_NEW_FAIL ("(*:0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEFG)XX", 0, G_REGEX_ERROR_NAME_TOO_LONG); ++ /* See https://gitlab.gnome.org/GNOME/gtksourceview/-/issues/278 */ ++ TEST_NEW_FAIL ("(?i-x)((?:(?i-x)[^\\x00\\t\\n\\f\\r \"'/<=>\\x{007F}-\\x{009F}" \ ++ "\\x{FDD0}-\\x{FDEF}\\x{FFFE}\\x{FFFF}\\x{1FFFE}\\x{1FFFF}" \ ++ "\\x{2FFFE}\\x{2FFFF}\\x{3FFFE}\\x{3FFFF}\\x{4FFFE}\\x{4FFFF}" \ ++ "\\x{5FFFE}\\x{5FFFF}\\x{6FFFE}\\x{6FFFF}\\x{7FFFE}\\x{7FFFF}" \ ++ "\\x{8FFFE}\\x{8FFFF}\\x{9FFFE}\\x{9FFFF}\\x{AFFFE}\\x{AFFFF}" \ ++ "\\x{BFFFE}\\x{BFFFF}\\x{CFFFE}\\x{CFFFF}\\x{DFFFE}\\x{DFFFF}" \ ++ "\\x{EFFFE}\\x{EFFFF}\\x{FFFFE}\\x{FFFFF}\\x{10FFFE}\\x{10FFFF}]+)" \ ++ "\\s*=\\s*)(\\\")", ++ G_REGEX_RAW, G_REGEX_ERROR_HEX_CODE_TOO_LARGE); + + /* These errors can't really be tested easily: + * G_REGEX_ERROR_EXPRESSION_TOO_LARGE +-- +GitLab + diff --git a/backport-regex-Avoid-allocating-offsets-until-we-ve-a-match.patch b/backport-regex-Avoid-allocating-offsets-until-we-ve-a-match.patch new file mode 100644 index 0000000000000000000000000000000000000000..f46b0af6db54a4acc59771f5f4a66a542b523f75 --- /dev/null +++ b/backport-regex-Avoid-allocating-offsets-until-we-ve-a-match.patch @@ -0,0 +1,38 @@ +From fe1c2628d52ca67ffe59420a0b4d371893795e62 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 19:19:03 +0200 +Subject: [PATCH] regex: Avoid allocating offsets until we've a match + +There's no much point of pre-allocating offsets given that we're doing +this when needed if only have matches to store. + +So let's just allocate the spaces for the dummy offset we depend on, +while allocate the others on demand. +--- + glib/gregex.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/glib/gregex.c b/glib/gregex.c +index 8a3be9076b..7d403ad53d 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -806,15 +806,11 @@ match_info_new (const GRegex *regex, + { + /* These values should be enough for most cases, if they are not + * enough g_regex_match_all_full() will expand them. */ +- match_info->n_offsets = 24; + match_info->n_workspace = 100; + match_info->workspace = g_new (gint, match_info->n_workspace); + } +- else +- { +- match_info->n_offsets = (match_info->n_subpatterns + 1) * 3; +- } + ++ match_info->n_offsets = 2; + match_info->offsets = g_new0 (gint, match_info->n_offsets); + /* Set an invalid position for the previous match. */ + match_info->offsets[0] = -1; +-- +GitLab + diff --git a/backport-regex-Compute-the-offsets-size-based-on-match-results.patch b/backport-regex-Compute-the-offsets-size-based-on-match-results.patch new file mode 100644 index 0000000000000000000000000000000000000000..8579bdaf2316c9eee34096458a543d17257dbbd2 --- /dev/null +++ b/backport-regex-Compute-the-offsets-size-based-on-match-results.patch @@ -0,0 +1,59 @@ +From e8628a7ed59e54b5a5e498de0375f101a4e76e64 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 19:05:24 +0200 +Subject: [PATCH] regex: Compute the offsets size based on match results + +While the ovector count would include all the allocated space, we only +care about the actual match values, so avoid wasting allocations and +just use the ones we need to hold the offsets. +--- + glib/gregex.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/glib/gregex.c b/glib/gregex.c +index cf86f0fe0d..8a3be9076b 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -832,10 +832,20 @@ recalc_match_offsets (GMatchInfo *match_info, + GError **error) + { + PCRE2_SIZE *ovector; ++ uint32_t ovector_size = 0; + uint32_t pre_n_offset; + uint32_t i; + +- if (pcre2_get_ovector_count (match_info->match_data) > G_MAXUINT32 / 2) ++ g_assert (!IS_PCRE2_ERROR (match_info->matches)); ++ ++ if (match_info->matches == PCRE2_ERROR_PARTIAL) ++ ovector_size = 1; ++ else if (match_info->matches > 0) ++ ovector_size = match_info->matches; ++ ++ g_assert (ovector_size != 0); ++ ++ if (pcre2_get_ovector_count (match_info->match_data) < ovector_size) + { + g_set_error (error, G_REGEX_ERROR, G_REGEX_ERROR_MATCH, + _("Error while matching regular expression %s: %s"), +@@ -844,7 +854,7 @@ recalc_match_offsets (GMatchInfo *match_info, + } + + pre_n_offset = match_info->n_offsets; +- match_info->n_offsets = pcre2_get_ovector_count (match_info->match_data) * 2; ++ match_info->n_offsets = ovector_size * 2; + ovector = pcre2_get_ovector_pointer (match_info->match_data); + + if (match_info->n_offsets != pre_n_offset) +@@ -2387,7 +2397,7 @@ g_regex_match_all_full (const GRegex *regex, + _("Error while matching regular expression %s: %s"), + regex->pattern, match_error (info->matches)); + } +- else if (info->matches > 0) ++ else if (info->matches != PCRE2_ERROR_NOMATCH) + { + if (!recalc_match_offsets (info, error)) + info->matches = PCRE2_ERROR_NOMATCH; +-- +GitLab + diff --git a/backport-regex-Do-not-mix-PCRE2-Compile-Match-Newline-and-BSR-flags.patch b/backport-regex-Do-not-mix-PCRE2-Compile-Match-Newline-and-BSR-flags.patch new file mode 100644 index 0000000000000000000000000000000000000000..d09aef854de1d5bcd697e02e4a4f1cd26b546789 --- /dev/null +++ b/backport-regex-Do-not-mix-PCRE2-Compile-Match-Newline-and-BSR-flags.patch @@ -0,0 +1,1062 @@ +From d639c4ec009537b743dcd2209184638d9f5d68b9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 14:49:10 +0200 +Subject: [PATCH] regex: Do not mix PCRE2 Compile, Match, Newline and BSR flags + +As per the PCRE2 port we still used to try to map the old GRegex flags +(PCRE1 based) with the new PCRE2 ones, but doing that we were also +mixing flags with enums, leading to unexpected behaviors when trying to +get new line and BSR options out of bigger flags arrays. + +So, avoid doing any mapping and store the values as native PCRE2 flags +internally and converting them back only when requested. + +This fixes some regressions on newline handling. + +Fixes: #2729 +Fixes: #2688 +Fixes: GNOME/gtksourceview#278 +--- + glib/gregex.c | 637 +++++++++++++++++++++++---------------------- + glib/tests/regex.c | 18 ++ + 2 files changed, 341 insertions(+), 314 deletions(-) + +diff --git a/glib/gregex.c b/glib/gregex.c +index a16ea98..95695f7 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -3,6 +3,7 @@ + * Copyright (C) 1999, 2000 Scott Wimer + * Copyright (C) 2004, Matthias Clasen + * Copyright (C) 2005 - 2007, Marco Barisione ++ * Copyright (C) 2022, Marco Trevisan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -108,62 +109,105 @@ + * library written by Philip Hazel. + */ + +-/* Signifies that flags have already been converted from pcre1 to pcre2. The +- * value 0x04000000u is also the value of PCRE2_MATCH_INVALID_UTF in pcre2.h, +- * but it is not used in gregex, so we can reuse it for this flag. +- */ +-#define G_REGEX_FLAGS_CONVERTED 0x04000000u ++#define G_REGEX_PCRE_GENERIC_MASK (PCRE2_ANCHORED | \ ++ PCRE2_NO_UTF_CHECK | \ ++ PCRE2_ENDANCHORED) ++ + /* Mask of all the possible values for GRegexCompileFlags. */ +-#define G_REGEX_COMPILE_MASK (PCRE2_CASELESS | \ +- PCRE2_MULTILINE | \ +- PCRE2_DOTALL | \ +- PCRE2_EXTENDED | \ +- PCRE2_ANCHORED | \ +- PCRE2_DOLLAR_ENDONLY | \ +- PCRE2_UNGREEDY | \ +- PCRE2_UTF | \ +- PCRE2_NO_AUTO_CAPTURE | \ +- PCRE2_FIRSTLINE | \ +- PCRE2_DUPNAMES | \ +- PCRE2_NEWLINE_CR | \ +- PCRE2_NEWLINE_LF | \ +- PCRE2_NEWLINE_CRLF | \ +- PCRE2_NEWLINE_ANYCRLF | \ +- PCRE2_BSR_ANYCRLF | \ +- G_REGEX_FLAGS_CONVERTED) +- +-/* Mask of all GRegexCompileFlags values that are (not) passed trough to PCRE */ +-#define G_REGEX_COMPILE_PCRE_MASK (G_REGEX_COMPILE_MASK & ~G_REGEX_COMPILE_NONPCRE_MASK) +-#define G_REGEX_COMPILE_NONPCRE_MASK (PCRE2_UTF | \ +- G_REGEX_FLAGS_CONVERTED) ++#define G_REGEX_COMPILE_MASK (G_REGEX_DEFAULT | \ ++ G_REGEX_CASELESS | \ ++ G_REGEX_MULTILINE | \ ++ G_REGEX_DOTALL | \ ++ G_REGEX_EXTENDED | \ ++ G_REGEX_ANCHORED | \ ++ G_REGEX_DOLLAR_ENDONLY | \ ++ G_REGEX_UNGREEDY | \ ++ G_REGEX_RAW | \ ++ G_REGEX_NO_AUTO_CAPTURE | \ ++ G_REGEX_OPTIMIZE | \ ++ G_REGEX_FIRSTLINE | \ ++ G_REGEX_DUPNAMES | \ ++ G_REGEX_NEWLINE_CR | \ ++ G_REGEX_NEWLINE_LF | \ ++ G_REGEX_NEWLINE_CRLF | \ ++ G_REGEX_NEWLINE_ANYCRLF | \ ++ G_REGEX_BSR_ANYCRLF) ++ ++#define G_REGEX_PCRE2_COMPILE_MASK (PCRE2_ALLOW_EMPTY_CLASS | \ ++ PCRE2_ALT_BSUX | \ ++ PCRE2_AUTO_CALLOUT | \ ++ PCRE2_CASELESS | \ ++ PCRE2_DOLLAR_ENDONLY | \ ++ PCRE2_DOTALL | \ ++ PCRE2_DUPNAMES | \ ++ PCRE2_EXTENDED | \ ++ PCRE2_FIRSTLINE | \ ++ PCRE2_MATCH_UNSET_BACKREF | \ ++ PCRE2_MULTILINE | \ ++ PCRE2_NEVER_UCP | \ ++ PCRE2_NEVER_UTF | \ ++ PCRE2_NO_AUTO_CAPTURE | \ ++ PCRE2_NO_AUTO_POSSESS | \ ++ PCRE2_NO_DOTSTAR_ANCHOR | \ ++ PCRE2_NO_START_OPTIMIZE | \ ++ PCRE2_UCP | \ ++ PCRE2_UNGREEDY | \ ++ PCRE2_UTF | \ ++ PCRE2_NEVER_BACKSLASH_C | \ ++ PCRE2_ALT_CIRCUMFLEX | \ ++ PCRE2_ALT_VERBNAMES | \ ++ PCRE2_USE_OFFSET_LIMIT | \ ++ PCRE2_EXTENDED_MORE | \ ++ PCRE2_LITERAL | \ ++ PCRE2_MATCH_INVALID_UTF | \ ++ G_REGEX_PCRE_GENERIC_MASK) ++ ++#define G_REGEX_COMPILE_NONPCRE_MASK (PCRE2_UTF) + + /* Mask of all the possible values for GRegexMatchFlags. */ +-#define G_REGEX_MATCH_MASK (PCRE2_ANCHORED | \ +- PCRE2_NOTBOL | \ +- PCRE2_NOTEOL | \ +- PCRE2_NOTEMPTY | \ +- PCRE2_NEWLINE_CR | \ +- PCRE2_NEWLINE_LF | \ +- PCRE2_NEWLINE_CRLF | \ +- PCRE2_NEWLINE_ANY | \ +- PCRE2_NEWLINE_ANYCRLF | \ +- PCRE2_BSR_ANYCRLF | \ +- PCRE2_BSR_UNICODE | \ +- PCRE2_PARTIAL_SOFT | \ +- PCRE2_PARTIAL_HARD | \ +- PCRE2_NOTEMPTY_ATSTART | \ +- G_REGEX_FLAGS_CONVERTED) +- ++#define G_REGEX_MATCH_MASK (G_REGEX_MATCH_DEFAULT | \ ++ G_REGEX_MATCH_ANCHORED | \ ++ G_REGEX_MATCH_NOTBOL | \ ++ G_REGEX_MATCH_NOTEOL | \ ++ G_REGEX_MATCH_NOTEMPTY | \ ++ G_REGEX_MATCH_PARTIAL | \ ++ G_REGEX_MATCH_NEWLINE_CR | \ ++ G_REGEX_MATCH_NEWLINE_LF | \ ++ G_REGEX_MATCH_NEWLINE_CRLF | \ ++ G_REGEX_MATCH_NEWLINE_ANY | \ ++ G_REGEX_MATCH_NEWLINE_ANYCRLF | \ ++ G_REGEX_MATCH_BSR_ANYCRLF | \ ++ G_REGEX_MATCH_BSR_ANY | \ ++ G_REGEX_MATCH_PARTIAL_SOFT | \ ++ G_REGEX_MATCH_PARTIAL_HARD | \ ++ G_REGEX_MATCH_NOTEMPTY_ATSTART) ++ ++#define G_REGEX_PCRE2_MATCH_MASK (PCRE2_NOTBOL |\ ++ PCRE2_NOTEOL |\ ++ PCRE2_NOTEMPTY |\ ++ PCRE2_NOTEMPTY_ATSTART |\ ++ PCRE2_PARTIAL_SOFT |\ ++ PCRE2_PARTIAL_HARD |\ ++ PCRE2_NO_JIT |\ ++ PCRE2_COPY_MATCHED_SUBJECT |\ ++ G_REGEX_PCRE_GENERIC_MASK) ++ ++/* TODO: Support PCRE2_NEWLINE_NUL */ + #define G_REGEX_NEWLINE_MASK (PCRE2_NEWLINE_CR | \ + PCRE2_NEWLINE_LF | \ + PCRE2_NEWLINE_CRLF | \ + PCRE2_NEWLINE_ANYCRLF) + +-#define G_REGEX_MATCH_NEWLINE_MASK (PCRE2_NEWLINE_CR | \ +- PCRE2_NEWLINE_LF | \ +- PCRE2_NEWLINE_CRLF | \ +- PCRE2_NEWLINE_ANYCRLF | \ +- PCRE2_NEWLINE_ANY) ++#define G_REGEX_COMPILE_NEWLINE_MASK (G_REGEX_NEWLINE_CR | \ ++ G_REGEX_NEWLINE_LF | \ ++ G_REGEX_NEWLINE_CRLF | \ ++ G_REGEX_NEWLINE_ANYCRLF) ++ ++#define G_REGEX_MATCH_NEWLINE_MASK (G_REGEX_MATCH_NEWLINE_CR | \ ++ G_REGEX_MATCH_NEWLINE_LF | \ ++ G_REGEX_MATCH_NEWLINE_CRLF | \ ++ G_REGEX_MATCH_NEWLINE_ANY | \ ++ G_REGEX_MATCH_NEWLINE_ANYCRLF) + + /* if the string is in UTF-8 use g_utf8_ functions, else use + * use just +/- 1. */ +@@ -178,7 +222,7 @@ struct _GMatchInfo + { + gint ref_count; /* the ref count (atomic) */ + GRegex *regex; /* the regex */ +- GRegexMatchFlags match_opts; /* options used at match time on the regex */ ++ uint32_t match_opts; /* pcre match options used at match time on the regex */ + gint matches; /* number of matching sub patterns, guaranteed to be <= (n_subpatterns + 1) if doing a single match (rather than matching all) */ + gint n_subpatterns; /* total number of sub patterns in the regex */ + gint pos; /* position in the string where last match left off */ +@@ -204,9 +248,10 @@ struct _GRegex + gint ref_count; /* the ref count for the immutable part (atomic) */ + gchar *pattern; /* the pattern */ + pcre2_code *pcre_re; /* compiled form of the pattern */ +- GRegexCompileFlags compile_opts; /* options used at compile time on the pattern, pcre2 values */ ++ uint32_t compile_opts; /* options used at compile time on the pattern, pcre2 values */ + GRegexCompileFlags orig_compile_opts; /* options used at compile time on the pattern, gregex values */ +- GRegexMatchFlags match_opts; /* options used at match time on the regex */ ++ uint32_t match_opts; /* pcre2 options used at match time on the regex */ ++ GRegexMatchFlags orig_match_opts; /* options used as default match options, gregex values */ + gint jit_options; /* options which were enabled for jit compiler */ + JITStatus jit_status; /* indicates the status of jit compiler for this compiled regex */ + }; +@@ -223,197 +268,182 @@ static GList *split_replacement (const gchar *replacement, + GError **error); + static void free_interpolation_data (InterpolationData *data); + +-static gint +-map_to_pcre2_compile_flags (gint pcre1_flags) ++static uint32_t ++get_pcre2_compile_options (GRegexCompileFlags compile_flags) + { +- /* Maps compile flags from pcre1 to pcre2 values +- */ +- gint pcre2_flags = G_REGEX_FLAGS_CONVERTED; +- +- if (pcre1_flags & G_REGEX_FLAGS_CONVERTED) +- return pcre1_flags; ++ /* Maps compile flags to pcre2 values */ ++ uint32_t pcre2_flags = 0; + +- if (pcre1_flags & G_REGEX_CASELESS) ++ if (compile_flags & G_REGEX_CASELESS) + pcre2_flags |= PCRE2_CASELESS; +- if (pcre1_flags & G_REGEX_MULTILINE) ++ if (compile_flags & G_REGEX_MULTILINE) + pcre2_flags |= PCRE2_MULTILINE; +- if (pcre1_flags & G_REGEX_DOTALL) ++ if (compile_flags & G_REGEX_DOTALL) + pcre2_flags |= PCRE2_DOTALL; +- if (pcre1_flags & G_REGEX_EXTENDED) ++ if (compile_flags & G_REGEX_EXTENDED) + pcre2_flags |= PCRE2_EXTENDED; +- if (pcre1_flags & G_REGEX_ANCHORED) ++ if (compile_flags & G_REGEX_ANCHORED) + pcre2_flags |= PCRE2_ANCHORED; +- if (pcre1_flags & G_REGEX_DOLLAR_ENDONLY) ++ if (compile_flags & G_REGEX_DOLLAR_ENDONLY) + pcre2_flags |= PCRE2_DOLLAR_ENDONLY; +- if (pcre1_flags & G_REGEX_UNGREEDY) ++ if (compile_flags & G_REGEX_UNGREEDY) + pcre2_flags |= PCRE2_UNGREEDY; +- if (!(pcre1_flags & G_REGEX_RAW)) ++ if (!(compile_flags & G_REGEX_RAW)) + pcre2_flags |= PCRE2_UTF; +- if (pcre1_flags & G_REGEX_NO_AUTO_CAPTURE) ++ if (compile_flags & G_REGEX_NO_AUTO_CAPTURE) + pcre2_flags |= PCRE2_NO_AUTO_CAPTURE; +- if (pcre1_flags & G_REGEX_FIRSTLINE) ++ if (compile_flags & G_REGEX_FIRSTLINE) + pcre2_flags |= PCRE2_FIRSTLINE; +- if (pcre1_flags & G_REGEX_DUPNAMES) ++ if (compile_flags & G_REGEX_DUPNAMES) + pcre2_flags |= PCRE2_DUPNAMES; +- if (pcre1_flags & G_REGEX_NEWLINE_CR) +- pcre2_flags |= PCRE2_NEWLINE_CR; +- if (pcre1_flags & G_REGEX_NEWLINE_LF) +- pcre2_flags |= PCRE2_NEWLINE_LF; +- /* Check for exact match for a composite flag */ +- if ((pcre1_flags & G_REGEX_NEWLINE_CRLF) == G_REGEX_NEWLINE_CRLF) +- pcre2_flags |= PCRE2_NEWLINE_CRLF; +- /* Check for exact match for a composite flag */ +- if ((pcre1_flags & G_REGEX_NEWLINE_ANYCRLF) == G_REGEX_NEWLINE_ANYCRLF) +- pcre2_flags |= PCRE2_NEWLINE_ANYCRLF; +- if (pcre1_flags & G_REGEX_BSR_ANYCRLF) +- pcre2_flags |= PCRE2_BSR_ANYCRLF; +- +- /* these are not available in pcre2, but we use G_REGEX_OPTIMIZE as a special +- * case to request JIT compilation */ +- if (pcre1_flags & G_REGEX_OPTIMIZE) +- pcre2_flags |= 0; +-G_GNUC_BEGIN_IGNORE_DEPRECATIONS +- if (pcre1_flags & G_REGEX_JAVASCRIPT_COMPAT) +- pcre2_flags |= 0; +-G_GNUC_END_IGNORE_DEPRECATIONS +- +- return pcre2_flags; ++ ++ return pcre2_flags & G_REGEX_PCRE2_COMPILE_MASK; + } + +-static gint +-map_to_pcre2_match_flags (gint pcre1_flags) ++static uint32_t ++get_pcre2_match_options (GRegexMatchFlags match_flags, ++ GRegexCompileFlags compile_flags) + { +- /* Maps match flags from pcre1 to pcre2 values +- */ +- gint pcre2_flags = G_REGEX_FLAGS_CONVERTED; +- +- if (pcre1_flags & G_REGEX_FLAGS_CONVERTED) +- return pcre1_flags; ++ /* Maps match flags to pcre2 values */ ++ uint32_t pcre2_flags = 0; + +- if (pcre1_flags & G_REGEX_MATCH_ANCHORED) ++ if (match_flags & G_REGEX_MATCH_ANCHORED) + pcre2_flags |= PCRE2_ANCHORED; +- if (pcre1_flags & G_REGEX_MATCH_NOTBOL) ++ if (match_flags & G_REGEX_MATCH_NOTBOL) + pcre2_flags |= PCRE2_NOTBOL; +- if (pcre1_flags & G_REGEX_MATCH_NOTEOL) ++ if (match_flags & G_REGEX_MATCH_NOTEOL) + pcre2_flags |= PCRE2_NOTEOL; +- if (pcre1_flags & G_REGEX_MATCH_NOTEMPTY) ++ if (match_flags & G_REGEX_MATCH_NOTEMPTY) + pcre2_flags |= PCRE2_NOTEMPTY; +- if (pcre1_flags & G_REGEX_MATCH_NEWLINE_CR) +- pcre2_flags |= PCRE2_NEWLINE_CR; +- if (pcre1_flags & G_REGEX_MATCH_NEWLINE_LF) +- pcre2_flags |= PCRE2_NEWLINE_LF; +- /* Check for exact match for a composite flag */ +- if ((pcre1_flags & G_REGEX_MATCH_NEWLINE_CRLF) == G_REGEX_MATCH_NEWLINE_CRLF) +- pcre2_flags |= PCRE2_NEWLINE_CRLF; +- if (pcre1_flags & G_REGEX_MATCH_NEWLINE_ANY) +- pcre2_flags |= PCRE2_NEWLINE_ANY; +- /* Check for exact match for a composite flag */ +- if ((pcre1_flags & G_REGEX_MATCH_NEWLINE_ANYCRLF) == G_REGEX_MATCH_NEWLINE_ANYCRLF) +- pcre2_flags |= PCRE2_NEWLINE_ANYCRLF; +- if (pcre1_flags & G_REGEX_MATCH_BSR_ANYCRLF) +- pcre2_flags |= PCRE2_BSR_ANYCRLF; +- if (pcre1_flags & G_REGEX_MATCH_BSR_ANY) +- pcre2_flags |= PCRE2_BSR_UNICODE; +- if (pcre1_flags & G_REGEX_MATCH_PARTIAL_SOFT) ++ if (match_flags & G_REGEX_MATCH_PARTIAL_SOFT) + pcre2_flags |= PCRE2_PARTIAL_SOFT; +- if (pcre1_flags & G_REGEX_MATCH_PARTIAL_HARD) ++ if (match_flags & G_REGEX_MATCH_PARTIAL_HARD) + pcre2_flags |= PCRE2_PARTIAL_HARD; +- if (pcre1_flags & G_REGEX_MATCH_NOTEMPTY_ATSTART) ++ if (match_flags & G_REGEX_MATCH_NOTEMPTY_ATSTART) + pcre2_flags |= PCRE2_NOTEMPTY_ATSTART; + +- return pcre2_flags; ++ if (compile_flags & G_REGEX_RAW) ++ pcre2_flags |= PCRE2_NO_UTF_CHECK; ++ ++ return pcre2_flags & G_REGEX_PCRE2_MATCH_MASK; + } + +-static gint +-map_to_pcre1_compile_flags (gint pcre2_flags) ++static GRegexCompileFlags ++g_regex_compile_flags_from_pcre2 (uint32_t pcre2_flags) + { +- /* Maps compile flags from pcre2 to pcre1 values +- */ +- gint pcre1_flags = 0; +- +- if (!(pcre2_flags & G_REGEX_FLAGS_CONVERTED)) +- return pcre2_flags; ++ GRegexCompileFlags compile_flags = G_REGEX_DEFAULT; + + if (pcre2_flags & PCRE2_CASELESS) +- pcre1_flags |= G_REGEX_CASELESS; ++ compile_flags |= G_REGEX_CASELESS; + if (pcre2_flags & PCRE2_MULTILINE) +- pcre1_flags |= G_REGEX_MULTILINE; ++ compile_flags |= G_REGEX_MULTILINE; + if (pcre2_flags & PCRE2_DOTALL) +- pcre1_flags |= G_REGEX_DOTALL; ++ compile_flags |= G_REGEX_DOTALL; + if (pcre2_flags & PCRE2_EXTENDED) +- pcre1_flags |= G_REGEX_EXTENDED; ++ compile_flags |= G_REGEX_EXTENDED; + if (pcre2_flags & PCRE2_ANCHORED) +- pcre1_flags |= G_REGEX_ANCHORED; ++ compile_flags |= G_REGEX_ANCHORED; + if (pcre2_flags & PCRE2_DOLLAR_ENDONLY) +- pcre1_flags |= G_REGEX_DOLLAR_ENDONLY; ++ compile_flags |= G_REGEX_DOLLAR_ENDONLY; + if (pcre2_flags & PCRE2_UNGREEDY) +- pcre1_flags |= G_REGEX_UNGREEDY; ++ compile_flags |= G_REGEX_UNGREEDY; + if (!(pcre2_flags & PCRE2_UTF)) +- pcre1_flags |= G_REGEX_RAW; ++ compile_flags |= G_REGEX_RAW; + if (pcre2_flags & PCRE2_NO_AUTO_CAPTURE) +- pcre1_flags |= G_REGEX_NO_AUTO_CAPTURE; ++ compile_flags |= G_REGEX_NO_AUTO_CAPTURE; + if (pcre2_flags & PCRE2_FIRSTLINE) +- pcre1_flags |= G_REGEX_FIRSTLINE; ++ compile_flags |= G_REGEX_FIRSTLINE; + if (pcre2_flags & PCRE2_DUPNAMES) +- pcre1_flags |= G_REGEX_DUPNAMES; +- if (pcre2_flags & PCRE2_NEWLINE_CR) +- pcre1_flags |= G_REGEX_NEWLINE_CR; +- if (pcre2_flags & PCRE2_NEWLINE_LF) +- pcre1_flags |= G_REGEX_NEWLINE_LF; +- /* Check for exact match for a composite flag */ +- if ((pcre2_flags & PCRE2_NEWLINE_CRLF) == PCRE2_NEWLINE_CRLF) +- pcre1_flags |= G_REGEX_NEWLINE_CRLF; +- /* Check for exact match for a composite flag */ +- if ((pcre2_flags & PCRE2_NEWLINE_ANYCRLF) == PCRE2_NEWLINE_ANYCRLF) +- pcre1_flags |= G_REGEX_NEWLINE_ANYCRLF; +- if (pcre2_flags & PCRE2_BSR_ANYCRLF) +- pcre1_flags |= G_REGEX_BSR_ANYCRLF; +- +- return pcre1_flags; ++ compile_flags |= G_REGEX_DUPNAMES; ++ ++ return compile_flags & G_REGEX_COMPILE_MASK; + } + +-static gint +-map_to_pcre1_match_flags (gint pcre2_flags) ++static GRegexMatchFlags ++g_regex_match_flags_from_pcre2 (uint32_t pcre2_flags) + { +- /* Maps match flags from pcre2 to pcre1 values +- */ +- gint pcre1_flags = 0; +- +- if (!(pcre2_flags & G_REGEX_FLAGS_CONVERTED)) +- return pcre2_flags; ++ GRegexMatchFlags match_flags = G_REGEX_MATCH_DEFAULT; + + if (pcre2_flags & PCRE2_ANCHORED) +- pcre1_flags |= G_REGEX_MATCH_ANCHORED; ++ match_flags |= G_REGEX_MATCH_ANCHORED; + if (pcre2_flags & PCRE2_NOTBOL) +- pcre1_flags |= G_REGEX_MATCH_NOTBOL; ++ match_flags |= G_REGEX_MATCH_NOTBOL; + if (pcre2_flags & PCRE2_NOTEOL) +- pcre1_flags |= G_REGEX_MATCH_NOTEOL; ++ match_flags |= G_REGEX_MATCH_NOTEOL; + if (pcre2_flags & PCRE2_NOTEMPTY) +- pcre1_flags |= G_REGEX_MATCH_NOTEMPTY; +- if (pcre2_flags & PCRE2_NEWLINE_CR) +- pcre1_flags |= G_REGEX_MATCH_NEWLINE_CR; +- if (pcre2_flags & PCRE2_NEWLINE_LF) +- pcre1_flags |= G_REGEX_MATCH_NEWLINE_LF; +- /* Check for exact match for a composite flag */ +- if ((pcre2_flags & PCRE2_NEWLINE_CRLF) == PCRE2_NEWLINE_CRLF) +- pcre1_flags |= G_REGEX_MATCH_NEWLINE_CRLF; +- if (pcre2_flags & PCRE2_NEWLINE_ANY) +- pcre1_flags |= G_REGEX_MATCH_NEWLINE_ANY; +- /* Check for exact match for a composite flag */ +- if ((pcre2_flags & PCRE2_NEWLINE_ANYCRLF) == PCRE2_NEWLINE_ANYCRLF) +- pcre1_flags |= G_REGEX_MATCH_NEWLINE_ANYCRLF; +- if (pcre2_flags & PCRE2_BSR_ANYCRLF) +- pcre1_flags |= G_REGEX_MATCH_BSR_ANYCRLF; +- if (pcre2_flags & PCRE2_BSR_UNICODE) +- pcre1_flags |= G_REGEX_MATCH_BSR_ANY; ++ match_flags |= G_REGEX_MATCH_NOTEMPTY; + if (pcre2_flags & PCRE2_PARTIAL_SOFT) +- pcre1_flags |= G_REGEX_MATCH_PARTIAL_SOFT; ++ match_flags |= G_REGEX_MATCH_PARTIAL_SOFT; + if (pcre2_flags & PCRE2_PARTIAL_HARD) +- pcre1_flags |= G_REGEX_MATCH_PARTIAL_HARD; ++ match_flags |= G_REGEX_MATCH_PARTIAL_HARD; + if (pcre2_flags & PCRE2_NOTEMPTY_ATSTART) +- pcre1_flags |= G_REGEX_MATCH_NOTEMPTY_ATSTART; ++ match_flags |= G_REGEX_MATCH_NOTEMPTY_ATSTART; ++ ++ return (match_flags & G_REGEX_MATCH_MASK); ++} ++ ++static uint32_t ++get_pcre2_newline_compile_options (GRegexCompileFlags compile_flags) ++{ ++ compile_flags &= G_REGEX_COMPILE_NEWLINE_MASK; ++ ++ switch (compile_flags) ++ { ++ case G_REGEX_NEWLINE_CR: ++ return PCRE2_NEWLINE_CR; ++ case G_REGEX_NEWLINE_LF: ++ return PCRE2_NEWLINE_LF; ++ case G_REGEX_NEWLINE_CRLF: ++ return PCRE2_NEWLINE_CRLF; ++ case G_REGEX_NEWLINE_ANYCRLF: ++ return PCRE2_NEWLINE_ANYCRLF; ++ default: ++ if (compile_flags != 0) ++ return 0; ++ ++ return PCRE2_NEWLINE_ANY; ++ } ++} ++ ++static uint32_t ++get_pcre2_newline_match_options (GRegexMatchFlags match_flags) ++{ ++ switch (match_flags & G_REGEX_MATCH_NEWLINE_MASK) ++ { ++ case G_REGEX_MATCH_NEWLINE_CR: ++ return PCRE2_NEWLINE_CR; ++ case G_REGEX_MATCH_NEWLINE_LF: ++ return PCRE2_NEWLINE_LF; ++ case G_REGEX_MATCH_NEWLINE_CRLF: ++ return PCRE2_NEWLINE_CRLF; ++ case G_REGEX_MATCH_NEWLINE_ANY: ++ return PCRE2_NEWLINE_ANY; ++ case G_REGEX_MATCH_NEWLINE_ANYCRLF: ++ return PCRE2_NEWLINE_ANYCRLF; ++ default: ++ return 0; ++ } ++} ++ ++static uint32_t ++get_pcre2_bsr_compile_options (GRegexCompileFlags compile_flags) ++{ ++ if (compile_flags & G_REGEX_BSR_ANYCRLF) ++ return PCRE2_BSR_ANYCRLF; + +- return pcre1_flags; ++ return PCRE2_BSR_UNICODE; ++} ++ ++static uint32_t ++get_pcre2_bsr_match_options (GRegexMatchFlags match_flags) ++{ ++ if (match_flags & G_REGEX_MATCH_BSR_ANYCRLF) ++ return PCRE2_BSR_ANYCRLF; ++ ++ if (match_flags & G_REGEX_MATCH_BSR_ANY) ++ return PCRE2_BSR_UNICODE; ++ ++ return 0; + } + + static const gchar * +@@ -742,12 +772,12 @@ translate_compile_error (gint *errcode, const gchar **errmsg) + /* GMatchInfo */ + + static GMatchInfo * +-match_info_new (const GRegex *regex, +- const gchar *string, +- gint string_len, +- gint start_position, +- gint match_options, +- gboolean is_dfa) ++match_info_new (const GRegex *regex, ++ const gchar *string, ++ gint string_len, ++ gint start_position, ++ GRegexMatchFlags match_options, ++ gboolean is_dfa) + { + GMatchInfo *match_info; + +@@ -761,7 +791,8 @@ match_info_new (const GRegex *regex, + match_info->string_len = string_len; + match_info->matches = PCRE2_ERROR_NOMATCH; + match_info->pos = start_position; +- match_info->match_opts = match_options; ++ match_info->match_opts = ++ get_pcre2_match_options (match_options, regex->orig_compile_opts); + + pcre2_pattern_info (regex->pcre_re, PCRE2_INFO_CAPTURECOUNT, + &match_info->n_subpatterns); +@@ -822,8 +853,8 @@ recalc_match_offsets (GMatchInfo *match_info, + } + + static void +-enable_jit_with_match_options (GRegex *regex, +- GRegexMatchFlags match_options) ++enable_jit_with_match_options (GRegex *regex, ++ uint32_t match_options) + { + gint old_jit_options, new_jit_options, retval; + +@@ -1009,7 +1040,7 @@ g_match_info_next (GMatchInfo *match_info, + return FALSE; + } + +- opts = map_to_pcre2_match_flags (match_info->regex->match_opts | match_info->match_opts); ++ opts = match_info->regex->match_opts | match_info->match_opts; + + enable_jit_with_match_options (match_info->regex, opts); + if (match_info->regex->jit_status == JIT_STATUS_ENABLED) +@@ -1018,7 +1049,7 @@ g_match_info_next (GMatchInfo *match_info, + (PCRE2_SPTR8) match_info->string, + match_info->string_len, + match_info->pos, +- opts & ~G_REGEX_FLAGS_CONVERTED, ++ opts, + match_info->match_data, + match_info->match_context); + } +@@ -1028,7 +1059,7 @@ g_match_info_next (GMatchInfo *match_info, + (PCRE2_SPTR8) match_info->string, + match_info->string_len, + match_info->pos, +- opts & ~G_REGEX_FLAGS_CONVERTED, ++ opts, + match_info->match_data, + match_info->match_context); + } +@@ -1563,14 +1594,14 @@ g_regex_unref (GRegex *regex) + } + } + +-/* +- * @match_options: (inout) (optional): +- */ +-static pcre2_code *regex_compile (const gchar *pattern, +- GRegexCompileFlags compile_options, +- GRegexCompileFlags *compile_options_out, +- GRegexMatchFlags *match_options, +- GError **error); ++static pcre2_code * regex_compile (const gchar *pattern, ++ uint32_t compile_options, ++ uint32_t newline_options, ++ uint32_t bsr_options, ++ GError **error); ++ ++static uint32_t get_pcre2_inline_compile_options (pcre2_code *re, ++ uint32_t compile_options); + + /** + * g_regex_new: +@@ -1596,11 +1627,10 @@ g_regex_new (const gchar *pattern, + GRegex *regex; + pcre2_code *re; + static gsize initialised = 0; +- GRegexCompileFlags orig_compile_opts; +- +- orig_compile_opts = compile_options; +- compile_options = map_to_pcre2_compile_flags (compile_options); +- match_options = map_to_pcre2_match_flags (match_options); ++ uint32_t pcre_compile_options; ++ uint32_t pcre_match_options; ++ uint32_t newline_options; ++ uint32_t bsr_options; + + g_return_val_if_fail (pattern != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); +@@ -1618,113 +1648,97 @@ g_regex_new (const gchar *pattern, + g_once_init_leave (&initialised, supports_utf8 ? 1 : 2); + } + +- if (G_UNLIKELY (initialised != 1)) ++ if (G_UNLIKELY (initialised != 1)) + { + g_set_error_literal (error, G_REGEX_ERROR, G_REGEX_ERROR_COMPILE, + _("PCRE library is compiled with incompatible options")); + return NULL; + } + +- switch (compile_options & G_REGEX_NEWLINE_MASK) ++ pcre_compile_options = get_pcre2_compile_options (compile_options); ++ pcre_match_options = get_pcre2_match_options (match_options, compile_options); ++ ++ newline_options = get_pcre2_newline_match_options (match_options); ++ if (newline_options == 0) ++ newline_options = get_pcre2_newline_compile_options (compile_options); ++ ++ if (newline_options == 0) + { +- case 0: /* PCRE2_NEWLINE_ANY */ +- case PCRE2_NEWLINE_CR: +- case PCRE2_NEWLINE_LF: +- case PCRE2_NEWLINE_CRLF: +- case PCRE2_NEWLINE_ANYCRLF: +- break; +- default: + g_set_error (error, G_REGEX_ERROR, G_REGEX_ERROR_INCONSISTENT_NEWLINE_OPTIONS, + "Invalid newline flags"); + return NULL; + } + +- re = regex_compile (pattern, compile_options, &compile_options, +- &match_options, error); ++ bsr_options = get_pcre2_bsr_match_options (match_options); ++ if (!bsr_options) ++ bsr_options = get_pcre2_bsr_compile_options (compile_options); ++ ++ re = regex_compile (pattern, pcre_compile_options, ++ newline_options, bsr_options, error); + if (re == NULL) + return NULL; + ++ pcre_compile_options |= ++ get_pcre2_inline_compile_options (re, pcre_compile_options); ++ + regex = g_new0 (GRegex, 1); + regex->ref_count = 1; + regex->pattern = g_strdup (pattern); + regex->pcre_re = re; +- regex->compile_opts = compile_options; +- regex->orig_compile_opts = orig_compile_opts; +- regex->match_opts = match_options; ++ regex->compile_opts = pcre_compile_options; ++ regex->orig_compile_opts = compile_options; ++ regex->match_opts = pcre_match_options; ++ regex->orig_match_opts = match_options; + enable_jit_with_match_options (regex, regex->match_opts); + + return regex; + } + +-static gint +-extract_newline_options (const GRegexCompileFlags compile_options, +- const GRegexMatchFlags *match_options) +-{ +- gint newline_options = PCRE2_NEWLINE_ANY; +- +- if (compile_options & G_REGEX_NEWLINE_MASK) +- newline_options = compile_options & G_REGEX_NEWLINE_MASK; +- if (match_options && *match_options & G_REGEX_MATCH_NEWLINE_MASK) +- newline_options = *match_options & G_REGEX_MATCH_NEWLINE_MASK; +- +- return newline_options; +-} +- +-static gint +-extract_bsr_options (const GRegexCompileFlags compile_options, +- const GRegexMatchFlags *match_options) +-{ +- gint bsr_options = PCRE2_BSR_UNICODE; +- +- if (compile_options & PCRE2_BSR_ANYCRLF) +- bsr_options = PCRE2_BSR_ANYCRLF; +- if (match_options && *match_options & PCRE2_BSR_ANYCRLF) +- bsr_options = PCRE2_BSR_ANYCRLF; +- if (match_options && *match_options & PCRE2_BSR_UNICODE) +- bsr_options = PCRE2_BSR_UNICODE; +- +- return bsr_options; +-} +- + static pcre2_code * +-regex_compile (const gchar *pattern, +- GRegexCompileFlags compile_options, +- GRegexCompileFlags *compile_options_out, +- GRegexMatchFlags *match_options, +- GError **error) ++regex_compile (const gchar *pattern, ++ uint32_t compile_options, ++ uint32_t newline_options, ++ uint32_t bsr_options, ++ GError **error) + { + pcre2_code *re; + pcre2_compile_context *context; + const gchar *errmsg; + PCRE2_SIZE erroffset; + gint errcode; +- GRegexCompileFlags nonpcre_compile_options; +- uint32_t pcre_compile_options; +- +- nonpcre_compile_options = compile_options & G_REGEX_COMPILE_NONPCRE_MASK; + + context = pcre2_compile_context_create (NULL); + + /* set newline options */ +- pcre2_set_newline (context, extract_newline_options (compile_options, match_options)); ++ if (pcre2_set_newline (context, newline_options) != 0) ++ { ++ g_set_error (error, G_REGEX_ERROR, ++ G_REGEX_ERROR_INCONSISTENT_NEWLINE_OPTIONS, ++ "Invalid newline flags"); ++ pcre2_compile_context_free (context); ++ return NULL; ++ } + + /* set bsr options */ +- pcre2_set_bsr (context, extract_bsr_options (compile_options, match_options)); ++ if (pcre2_set_bsr (context, bsr_options) != 0) ++ { ++ g_set_error (error, G_REGEX_ERROR, ++ G_REGEX_ERROR_INCONSISTENT_NEWLINE_OPTIONS, ++ "Invalid BSR flags"); ++ pcre2_compile_context_free (context); ++ return NULL; ++ } + + /* In case UTF-8 mode is used, also set PCRE2_NO_UTF_CHECK */ + if (compile_options & PCRE2_UTF) +- { +- compile_options |= PCRE2_NO_UTF_CHECK; +- if (match_options != NULL) +- *match_options |= PCRE2_NO_UTF_CHECK; +- } ++ compile_options |= PCRE2_NO_UTF_CHECK; + + compile_options |= PCRE2_UCP; + + /* compile the pattern */ + re = pcre2_compile ((PCRE2_SPTR8) pattern, + PCRE2_ZERO_TERMINATED, +- compile_options & ~G_REGEX_FLAGS_CONVERTED, ++ compile_options, + &errcode, + &erroffset, + context); +@@ -1755,16 +1769,22 @@ regex_compile (const gchar *pattern, + return NULL; + } + ++ return re; ++} ++ ++static uint32_t ++get_pcre2_inline_compile_options (pcre2_code *re, ++ uint32_t compile_options) ++{ ++ uint32_t pcre_compile_options; ++ uint32_t nonpcre_compile_options; ++ + /* For options set at the beginning of the pattern, pcre puts them into + * compile options, e.g. "(?i)foo" will make the pcre structure store + * PCRE2_CASELESS even though it wasn't explicitly given for compilation. */ ++ nonpcre_compile_options = compile_options & G_REGEX_COMPILE_NONPCRE_MASK; + pcre2_pattern_info (re, PCRE2_INFO_ALLOPTIONS, &pcre_compile_options); +- compile_options = pcre_compile_options & G_REGEX_COMPILE_PCRE_MASK; +- +- /* Don't leak PCRE2_NEWLINE_ANY, which is part of PCRE2_NEWLINE_ANYCRLF */ +- if ((pcre_compile_options & PCRE2_NEWLINE_ANYCRLF) != PCRE2_NEWLINE_ANYCRLF) +- compile_options &= ~PCRE2_NEWLINE_ANY; +- ++ compile_options = pcre_compile_options & G_REGEX_PCRE2_COMPILE_MASK; + compile_options |= nonpcre_compile_options; + + if (!(compile_options & PCRE2_DUPNAMES)) +@@ -1775,10 +1795,7 @@ regex_compile (const gchar *pattern, + compile_options |= PCRE2_DUPNAMES; + } + +- if (compile_options_out != 0) +- *compile_options_out = compile_options; +- +- return re; ++ return compile_options; + } + + /** +@@ -1940,7 +1957,7 @@ g_regex_get_compile_flags (const GRegex *regex) + break; + } + +- return map_to_pcre1_compile_flags (regex->compile_opts) | extra_flags; ++ return g_regex_compile_flags_from_pcre2 (regex->compile_opts) | extra_flags; + } + + /** +@@ -1956,9 +1973,15 @@ g_regex_get_compile_flags (const GRegex *regex) + GRegexMatchFlags + g_regex_get_match_flags (const GRegex *regex) + { ++ uint32_t flags; ++ + g_return_val_if_fail (regex != NULL, 0); + +- return map_to_pcre1_match_flags (regex->match_opts & G_REGEX_MATCH_MASK); ++ flags = g_regex_match_flags_from_pcre2 (regex->match_opts); ++ flags |= (regex->orig_match_opts & G_REGEX_MATCH_NEWLINE_MASK); ++ flags |= (regex->orig_match_opts & (G_REGEX_MATCH_BSR_ANY | G_REGEX_MATCH_BSR_ANYCRLF)); ++ ++ return flags; + } + + /** +@@ -1992,9 +2015,6 @@ g_regex_match_simple (const gchar *pattern, + GRegex *regex; + gboolean result; + +- compile_options = map_to_pcre2_compile_flags (compile_options); +- match_options = map_to_pcre2_match_flags (match_options); +- + regex = g_regex_new (pattern, compile_options, G_REGEX_MATCH_DEFAULT, NULL); + if (!regex) + return FALSE; +@@ -2062,8 +2082,6 @@ g_regex_match (const GRegex *regex, + GRegexMatchFlags match_options, + GMatchInfo **match_info) + { +- match_options = map_to_pcre2_match_flags (match_options); +- + return g_regex_match_full (regex, string, -1, 0, match_options, + match_info, NULL); + } +@@ -2147,8 +2165,6 @@ g_regex_match_full (const GRegex *regex, + GMatchInfo *info; + gboolean match_ok; + +- match_options = map_to_pcre2_match_flags (match_options); +- + g_return_val_if_fail (regex != NULL, FALSE); + g_return_val_if_fail (string != NULL, FALSE); + g_return_val_if_fail (start_position >= 0, FALSE); +@@ -2199,8 +2215,6 @@ g_regex_match_all (const GRegex *regex, + GRegexMatchFlags match_options, + GMatchInfo **match_info) + { +- match_options = map_to_pcre2_match_flags (match_options); +- + return g_regex_match_all_full (regex, string, -1, 0, match_options, + match_info, NULL); + } +@@ -2272,8 +2286,8 @@ g_regex_match_all_full (const GRegex *regex, + gboolean done; + pcre2_code *pcre_re; + gboolean retval; +- +- match_options = map_to_pcre2_match_flags (match_options); ++ uint32_t newline_options; ++ uint32_t bsr_options; + + g_return_val_if_fail (regex != NULL, FALSE); + g_return_val_if_fail (string != NULL, FALSE); +@@ -2281,6 +2295,14 @@ g_regex_match_all_full (const GRegex *regex, + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail ((match_options & ~G_REGEX_MATCH_MASK) == 0, FALSE); + ++ newline_options = get_pcre2_newline_match_options (match_options); ++ if (!newline_options) ++ newline_options = get_pcre2_newline_compile_options (regex->orig_compile_opts); ++ ++ bsr_options = get_pcre2_bsr_match_options (match_options); ++ if (!bsr_options) ++ bsr_options = get_pcre2_bsr_compile_options (regex->orig_compile_opts); ++ + /* For PCRE2 we need to turn off PCRE2_NO_AUTO_POSSESS, which is an + * optimization for normal regex matching, but results in omitting some + * shorter matches here, and an observable behaviour change. +@@ -2289,7 +2311,7 @@ g_regex_match_all_full (const GRegex *regex, + * codesearch.debian.net, so don't bother caching the recompiled RE. */ + pcre_re = regex_compile (regex->pattern, + regex->compile_opts | PCRE2_NO_AUTO_POSSESS, +- NULL, NULL, error); ++ newline_options, bsr_options, error); + if (pcre_re == NULL) + return FALSE; + +@@ -2303,7 +2325,7 @@ g_regex_match_all_full (const GRegex *regex, + info->matches = pcre2_dfa_match (pcre_re, + (PCRE2_SPTR8) info->string, info->string_len, + info->pos, +- (regex->match_opts | match_options | PCRE2_NO_UTF_CHECK) & ~G_REGEX_FLAGS_CONVERTED, ++ (regex->match_opts | info->match_opts), + info->match_data, + info->match_context, + info->workspace, info->n_workspace); +@@ -2436,9 +2458,6 @@ g_regex_split_simple (const gchar *pattern, + GRegex *regex; + gchar **result; + +- compile_options = map_to_pcre2_compile_flags (compile_options); +- match_options = map_to_pcre2_match_flags (match_options); +- + regex = g_regex_new (pattern, compile_options, 0, NULL); + if (!regex) + return NULL; +@@ -2482,8 +2501,6 @@ g_regex_split (const GRegex *regex, + const gchar *string, + GRegexMatchFlags match_options) + { +- match_options = map_to_pcre2_match_flags (match_options); +- + return g_regex_split_full (regex, string, -1, 0, + match_options, 0, NULL); + } +@@ -2548,8 +2565,6 @@ g_regex_split_full (const GRegex *regex, + /* the returned array of char **s */ + gchar **string_list; + +- match_options = map_to_pcre2_match_flags (match_options); +- + g_return_val_if_fail (regex != NULL, NULL); + g_return_val_if_fail (string != NULL, NULL); + g_return_val_if_fail (start_position >= 0, NULL); +@@ -3174,8 +3189,6 @@ g_regex_replace (const GRegex *regex, + GList *list; + GError *tmp_error = NULL; + +- match_options = map_to_pcre2_match_flags (match_options); +- + g_return_val_if_fail (regex != NULL, NULL); + g_return_val_if_fail (string != NULL, NULL); + g_return_val_if_fail (start_position >= 0, NULL); +@@ -3245,8 +3258,6 @@ g_regex_replace_literal (const GRegex *regex, + GRegexMatchFlags match_options, + GError **error) + { +- match_options = map_to_pcre2_match_flags (match_options); +- + g_return_val_if_fail (replacement != NULL, NULL); + g_return_val_if_fail ((match_options & ~G_REGEX_MATCH_MASK) == 0, NULL); + +@@ -3335,8 +3346,6 @@ g_regex_replace_eval (const GRegex *regex, + gboolean done = FALSE; + GError *tmp_error = NULL; + +- match_options = map_to_pcre2_match_flags (match_options); +- + g_return_val_if_fail (regex != NULL, NULL); + g_return_val_if_fail (string != NULL, NULL); + g_return_val_if_fail (start_position >= 0, NULL); +diff --git a/glib/tests/regex.c b/glib/tests/regex.c +index 0d01d59..79e6b4a 100644 +--- a/glib/tests/regex.c ++++ b/glib/tests/regex.c +@@ -1,6 +1,7 @@ + /* + * Copyright (C) 2005 - 2006, Marco Barisione + * Copyright (C) 2010 Red Hat, Inc. ++ * Copyright (C) 2022, Marco Trevisan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -2353,7 +2354,13 @@ main (int argc, char *argv[]) + + /* TEST_NEW_CHECK_FLAGS(pattern, compile_opts, match_ops, real_compile_opts, real_match_opts) */ + TEST_NEW_CHECK_FLAGS ("a", G_REGEX_OPTIMIZE, 0, G_REGEX_OPTIMIZE, 0); ++ TEST_NEW_CHECK_FLAGS ("a", G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, ++ G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY); ++ TEST_NEW_CHECK_FLAGS ("a", 0, G_REGEX_MATCH_NEWLINE_ANYCRLF | G_REGEX_MATCH_BSR_ANYCRLF, ++ G_REGEX_NEWLINE_ANYCRLF | G_REGEX_BSR_ANYCRLF, ++ G_REGEX_MATCH_NEWLINE_ANYCRLF | G_REGEX_MATCH_BSR_ANYCRLF); + TEST_NEW_CHECK_FLAGS ("a", G_REGEX_RAW, 0, G_REGEX_RAW, 0); ++ TEST_NEW_CHECK_FLAGS ("(?J)a", 0, 0, G_REGEX_DUPNAMES, 0); + TEST_NEW_CHECK_FLAGS ("^.*", 0, 0, G_REGEX_ANCHORED, 0); + TEST_NEW_CHECK_FLAGS ("(*UTF8)a", 0, 0, 0 /* this is the default in GRegex */, 0); + TEST_NEW_CHECK_FLAGS ("(*UCP)a", 0, 0, 0 /* this always on in GRegex */, 0); +@@ -2559,6 +2566,8 @@ main (int argc, char *argv[]) + TEST_MATCH("^b$", G_REGEX_MULTILINE | G_REGEX_NEWLINE_CR, 0, "a\rb\rc", -1, 0, 0, TRUE); + TEST_MATCH("^b$", G_REGEX_MULTILINE | G_REGEX_NEWLINE_LF, 0, "a\rb\rc", -1, 0, 0, FALSE); + TEST_MATCH("^b$", G_REGEX_MULTILINE | G_REGEX_NEWLINE_CRLF, 0, "a\rb\rc", -1, 0, 0, FALSE); ++ TEST_MATCH("^b$", G_REGEX_MULTILINE | G_REGEX_NEWLINE_ANYCRLF, 0, "a\r\nb\nc", -1, 0, 0, TRUE); ++ TEST_MATCH("^b$", G_REGEX_MULTILINE | G_REGEX_NEWLINE_ANYCRLF, 0, "a\r\nb\rc", -1, 0, 0, TRUE); + TEST_MATCH("^b$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_CR, "a\nb\nc", -1, 0, 0, FALSE); + TEST_MATCH("^b$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_LF, "a\nb\nc", -1, 0, 0, TRUE); + TEST_MATCH("^b$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_CRLF, "a\nb\nc", -1, 0, 0, FALSE); +@@ -2568,6 +2577,8 @@ main (int argc, char *argv[]) + TEST_MATCH("^b$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_CR, "a\rb\rc", -1, 0, 0, TRUE); + TEST_MATCH("^b$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_LF, "a\rb\rc", -1, 0, 0, FALSE); + TEST_MATCH("^b$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_CRLF, "a\rb\rc", -1, 0, 0, FALSE); ++ TEST_MATCH("^b$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_ANYCRLF, "a\r\nb\rc", -1, 0, 0, TRUE); ++ TEST_MATCH("^b$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_ANYCRLF, "a\r\nb\nc", -1, 0, 0, TRUE); + + TEST_MATCH("^b$", G_REGEX_MULTILINE | G_REGEX_NEWLINE_CR, G_REGEX_MATCH_NEWLINE_ANY, "a\nb\nc", -1, 0, 0, TRUE); + TEST_MATCH("^b$", G_REGEX_MULTILINE | G_REGEX_NEWLINE_CR, G_REGEX_MATCH_NEWLINE_ANY, "a\rb\rc", -1, 0, 0, TRUE); +@@ -2577,6 +2588,13 @@ main (int argc, char *argv[]) + TEST_MATCH("^b$", G_REGEX_MULTILINE | G_REGEX_NEWLINE_CR, G_REGEX_MATCH_NEWLINE_CRLF, "a\r\nb\r\nc", -1, 0, 0, TRUE); + TEST_MATCH("^b$", G_REGEX_MULTILINE | G_REGEX_NEWLINE_CR, G_REGEX_MATCH_NEWLINE_CRLF, "a\rb\rc", -1, 0, 0, FALSE); + ++ /* See https://gitlab.gnome.org/GNOME/glib/-/issues/2729#note_1544130 */ ++ TEST_MATCH("^a$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_ANY, "a", -1, 0, 0, TRUE); ++ TEST_MATCH("^a$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_LF, "a", -1, 0, 0, TRUE); ++ TEST_MATCH("^a$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_CR, "a", -1, 0, 0, TRUE); ++ TEST_MATCH("^a$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_CRLF, "a", -1, 0, 0, TRUE); ++ TEST_MATCH("^a$", G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_ANYCRLF, "a", -1, 0, 0, TRUE); ++ + TEST_MATCH("a#\nb", G_REGEX_EXTENDED, 0, "a", -1, 0, 0, FALSE); + TEST_MATCH("a#\r\nb", G_REGEX_EXTENDED, 0, "a", -1, 0, 0, FALSE); + TEST_MATCH("a#\rb", G_REGEX_EXTENDED, 0, "a", -1, 0, 0, FALSE); +-- +2.33.0 +GitLab diff --git a/backport-regex-Do-not-use-JIT-when-using-unsupported-match-options.patch b/backport-regex-Do-not-use-JIT-when-using-unsupported-match-options.patch new file mode 100644 index 0000000000000000000000000000000000000000..57b4c7dcfad0e4f061c7bd0674ba70047f2b6bed --- /dev/null +++ b/backport-regex-Do-not-use-JIT-when-using-unsupported-match-options.patch @@ -0,0 +1,241 @@ +From bec68b2d74853de5e23ee40c890433fa336ffbc5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 9 Sep 2022 18:30:15 +0200 +Subject: [PATCH] glib/regex: Do not use JIT when using unsupported match + options + +Do not store jit status for regex unless during initial compilation. +After that, decide whether to use it depending on matching options. + +In fact there are some matching options that are incompatible with JIT, +as the PCRE2 docs states: + + Setting PCRE2_ANCHORED or PCRE2_ENDANCHORED at match time is not + supported by the just-in-time (JIT) compiler. If it is set, JIT + matching is disabled and the interpretive code in pcre2_match() is + run. Apart from PCRE2_NO_JIT (obviously), the remaining options are + supported for JIT matching. + +Fixes: GNOME/gtksourceview#283 +--- + glib/gregex.c | 38 ++++++++++++++++--------- + glib/tests/regex.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 94 insertions(+), 13 deletions(-) + +diff --git a/glib/gregex.c b/glib/gregex.c +index fe7473e628..220a1a11ac 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -201,6 +201,13 @@ + PCRE2_NEWLINE_CRLF | \ + PCRE2_NEWLINE_ANYCRLF) + ++/* Some match options are not supported when using JIT as stated in the ++ * pcre2jit man page under the 芦UNSUPPORTED OPTIONS AND PATTERN ITEMS禄 section: ++ * https://www.pcre.org/current/doc/html/pcre2jit.html#SEC5 ++ */ ++#define G_REGEX_PCRE2_JIT_UNSUPPORTED_OPTIONS (PCRE2_ANCHORED | \ ++ PCRE2_ENDANCHORED) ++ + #define G_REGEX_COMPILE_NEWLINE_MASK (G_REGEX_NEWLINE_CR | \ + G_REGEX_NEWLINE_LF | \ + G_REGEX_NEWLINE_CRLF | \ +@@ -869,7 +876,7 @@ recalc_match_offsets (GMatchInfo *match_info, + return TRUE; + } + +-static void ++static JITStatus + enable_jit_with_match_options (GRegex *regex, + uint32_t match_options) + { +@@ -877,9 +884,13 @@ enable_jit_with_match_options (GRegex *regex, + uint32_t old_jit_options, new_jit_options; + + if (!(regex->orig_compile_opts & G_REGEX_OPTIMIZE)) +- return; ++ return JIT_STATUS_DISABLED; ++ + if (regex->jit_status == JIT_STATUS_DISABLED) +- return; ++ return JIT_STATUS_DISABLED; ++ ++ if (match_options & G_REGEX_PCRE2_JIT_UNSUPPORTED_OPTIONS) ++ return JIT_STATUS_DISABLED; + + old_jit_options = regex->jit_options; + new_jit_options = old_jit_options | PCRE2_JIT_COMPLETE; +@@ -890,34 +901,34 @@ enable_jit_with_match_options (GRegex *regex, + + /* no new options enabled */ + if (new_jit_options == old_jit_options) +- return; ++ return regex->jit_status; + + retval = pcre2_jit_compile (regex->pcre_re, new_jit_options); + switch (retval) + { + case 0: /* JIT enabled successfully */ +- regex->jit_status = JIT_STATUS_ENABLED; + regex->jit_options = new_jit_options; +- break; ++ return JIT_STATUS_ENABLED; + case PCRE2_ERROR_NOMEMORY: + g_debug ("JIT compilation was requested with G_REGEX_OPTIMIZE, " + "but JIT was unable to allocate executable memory for the " + "compiler. Falling back to interpretive code."); +- regex->jit_status = JIT_STATUS_DISABLED; +- break; ++ return JIT_STATUS_DISABLED; + case PCRE2_ERROR_JIT_BADOPTION: + g_debug ("JIT compilation was requested with G_REGEX_OPTIMIZE, " + "but JIT support is not available. Falling back to " + "interpretive code."); +- regex->jit_status = JIT_STATUS_DISABLED; ++ return JIT_STATUS_DISABLED; + break; + default: + g_debug ("JIT compilation was requested with G_REGEX_OPTIMIZE, " + "but request for JIT support had unexpectedly failed (error %d). " + "Falling back to interpretive code.", retval); +- regex->jit_status = JIT_STATUS_DISABLED; ++ return JIT_STATUS_DISABLED; + break; + } ++ ++ return regex->jit_status; + } + + /** +@@ -1039,6 +1050,7 @@ gboolean + g_match_info_next (GMatchInfo *match_info, + GError **error) + { ++ JITStatus jit_status; + gint prev_match_start; + gint prev_match_end; + uint32_t opts; +@@ -1060,8 +1072,8 @@ g_match_info_next (GMatchInfo *match_info, + + opts = match_info->regex->match_opts | match_info->match_opts; + +- enable_jit_with_match_options (match_info->regex, opts); +- if (match_info->regex->jit_status == JIT_STATUS_ENABLED) ++ jit_status = enable_jit_with_match_options (match_info->regex, opts); ++ if (jit_status == JIT_STATUS_ENABLED) + { + match_info->matches = pcre2_jit_match (match_info->regex->pcre_re, + (PCRE2_SPTR8) match_info->string, +@@ -1727,7 +1739,7 @@ g_regex_new (const gchar *pattern, + regex->orig_compile_opts = compile_options; + regex->match_opts = pcre_match_options; + regex->orig_match_opts = match_options; +- enable_jit_with_match_options (regex, regex->match_opts); ++ regex->jit_status = enable_jit_with_match_options (regex, regex->match_opts); + + return regex; + } +diff --git a/glib/tests/regex.c b/glib/tests/regex.c +index 26844d63a7..2052ba0204 100644 +--- a/glib/tests/regex.c ++++ b/glib/tests/regex.c +@@ -2334,6 +2334,67 @@ test_compile_errors (void) + g_clear_error (&error); + } + ++static void ++test_jit_unsupported_matching_options (void) ++{ ++ GRegex *regex; ++ GMatchInfo *info; ++ gchar *substring; ++ ++ regex = g_regex_new ("(\\w+)#(\\w+)", G_REGEX_OPTIMIZE, G_REGEX_MATCH_DEFAULT, NULL); ++ ++ g_assert_true (g_regex_match (regex, "aa#bb cc#dd", G_REGEX_MATCH_DEFAULT, &info)); ++ g_assert_cmpint (g_match_info_get_match_count (info), ==, 3); ++ substring = g_match_info_fetch (info, 1); ++ g_assert_cmpstr (substring, ==, "aa"); ++ g_clear_pointer (&substring, g_free); ++ substring = g_match_info_fetch (info, 2); ++ g_assert_cmpstr (substring, ==, "bb"); ++ g_clear_pointer (&substring, g_free); ++ g_assert_true (g_match_info_next (info, NULL)); ++ g_assert_cmpint (g_match_info_get_match_count (info), ==, 3); ++ substring = g_match_info_fetch (info, 1); ++ g_assert_cmpstr (substring, ==, "cc"); ++ g_clear_pointer (&substring, g_free); ++ substring = g_match_info_fetch (info, 2); ++ g_assert_cmpstr (substring, ==, "dd"); ++ g_clear_pointer (&substring, g_free); ++ g_assert_false (g_match_info_next (info, NULL)); ++ g_match_info_free (info); ++ ++ g_assert_true (g_regex_match (regex, "aa#bb cc#dd", G_REGEX_MATCH_ANCHORED, &info)); ++ g_assert_cmpint (g_match_info_get_match_count (info), ==, 3); ++ substring = g_match_info_fetch (info, 1); ++ g_assert_cmpstr (substring, ==, "aa"); ++ g_clear_pointer (&substring, g_free); ++ substring = g_match_info_fetch (info, 2); ++ g_assert_cmpstr (substring, ==, "bb"); ++ g_clear_pointer (&substring, g_free); ++ g_assert_false (g_match_info_next (info, NULL)); ++ g_match_info_free (info); ++ ++ g_assert_true (g_regex_match (regex, "aa#bb cc#dd", G_REGEX_MATCH_DEFAULT, &info)); ++ g_assert_cmpint (g_match_info_get_match_count (info), ==, 3); ++ substring = g_match_info_fetch (info, 1); ++ g_assert_cmpstr (substring, ==, "aa"); ++ g_clear_pointer (&substring, g_free); ++ substring = g_match_info_fetch (info, 2); ++ g_assert_cmpstr (substring, ==, "bb"); ++ g_clear_pointer (&substring, g_free); ++ g_assert_true (g_match_info_next (info, NULL)); ++ g_assert_cmpint (g_match_info_get_match_count (info), ==, 3); ++ substring = g_match_info_fetch (info, 1); ++ g_assert_cmpstr (substring, ==, "cc"); ++ g_clear_pointer (&substring, g_free); ++ substring = g_match_info_fetch (info, 2); ++ g_assert_cmpstr (substring, ==, "dd"); ++ g_clear_pointer (&substring, g_free); ++ g_assert_false (g_match_info_next (info, NULL)); ++ g_match_info_free (info); ++ ++ g_regex_unref (regex); ++} ++ + int + main (int argc, char *argv[]) + { +@@ -2352,6 +2413,7 @@ main (int argc, char *argv[]) + g_test_add_func ("/regex/explicit-crlf", test_explicit_crlf); + g_test_add_func ("/regex/max-lookbehind", test_max_lookbehind); + g_test_add_func ("/regex/compile-errors", test_compile_errors); ++ g_test_add_func ("/regex/jit-unsupported-matching", test_jit_unsupported_matching_options); + + /* TEST_NEW(pattern, compile_opts, match_opts) */ + TEST_NEW("[A-Z]+", G_REGEX_CASELESS | G_REGEX_EXTENDED | G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTBOL | G_REGEX_MATCH_PARTIAL); +@@ -2488,6 +2550,7 @@ main (int argc, char *argv[]) + TEST_MATCH_SIMPLE("a", "ab", 0, G_REGEX_MATCH_ANCHORED, TRUE); + TEST_MATCH_SIMPLE("a", "a", G_REGEX_CASELESS, 0, TRUE); + TEST_MATCH_SIMPLE("a", "A", G_REGEX_CASELESS, 0, TRUE); ++ TEST_MATCH_SIMPLE("\\C\\C", "ab", G_REGEX_OPTIMIZE | G_REGEX_RAW, 0, TRUE); + /* These are needed to test extended properties. */ + TEST_MATCH_SIMPLE(AGRAVE, AGRAVE, G_REGEX_CASELESS, 0, TRUE); + TEST_MATCH_SIMPLE(AGRAVE, AGRAVE_UPPER, G_REGEX_CASELESS, 0, TRUE); +@@ -2947,6 +3010,12 @@ main (int argc, char *argv[]) + TEST_REPLACE("\\S+", "hello world", 0, "\\U-\\0-", "-HELLO- -WORLD-"); + TEST_REPLACE(".", "a", 0, "\\A", NULL); + TEST_REPLACE(".", "a", 0, "\\g", NULL); ++ TEST_REPLACE_OPTIONS("(\\w+)#(\\w+)", "aa#bb cc#dd", 0, "\\2#\\1", "bb#aa dd#cc", ++ G_REGEX_OPTIMIZE|G_REGEX_MULTILINE|G_REGEX_CASELESS, ++ 0); ++ TEST_REPLACE_OPTIONS("(\\w+)#(\\w+)", "aa#bb cc#dd", 0, "\\2#\\1", "bb#aa cc#dd", ++ G_REGEX_OPTIMIZE|G_REGEX_MULTILINE|G_REGEX_CASELESS, ++ G_REGEX_MATCH_ANCHORED); + + /* TEST_REPLACE_LIT(pattern, string, start_position, replacement, expected) */ + TEST_REPLACE_LIT("a", "ababa", 0, "A", "AbAbA"); +-- +GitLab + diff --git a/backport-regex-Handle-JIT-errors-more-explicitly.patch b/backport-regex-Handle-JIT-errors-more-explicitly.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1d61315551da8a10953994207457cd51bf915b7 --- /dev/null +++ b/backport-regex-Handle-JIT-errors-more-explicitly.patch @@ -0,0 +1,35 @@ +From 5e76cde5ffeac79b939cf84202024859cda5e753 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 7 Sep 2022 14:18:14 +0200 +Subject: [PATCH] regex: Handle JIT errors more explicitly + +--- + glib/gregex.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/glib/gregex.c b/glib/gregex.c +index 7d403ad53d..fe7473e628 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -471,6 +471,7 @@ match_error (gint errcode) + /* not used by pcre2_match() */ + break; + case PCRE2_ERROR_MATCHLIMIT: ++ case PCRE2_ERROR_JIT_STACKLIMIT: + return _("backtracking limit reached"); + case PCRE2_ERROR_CALLOUT: + /* callouts are not implemented */ +@@ -912,8 +913,8 @@ enable_jit_with_match_options (GRegex *regex, + break; + default: + g_debug ("JIT compilation was requested with G_REGEX_OPTIMIZE, " +- "but request for JIT support had unexpectedly failed. " +- "Falling back to interpretive code."); ++ "but request for JIT support had unexpectedly failed (error %d). " ++ "Falling back to interpretive code.", retval); + regex->jit_status = JIT_STATUS_DISABLED; + break; + } +-- +GitLab + diff --git a/backport-regex-Make-possible-to-test-replacements-with-options.patch b/backport-regex-Make-possible-to-test-replacements-with-options.patch new file mode 100644 index 0000000000000000000000000000000000000000..d9bed10e308f4d001c00099cdb671c362c9c3b7a --- /dev/null +++ b/backport-regex-Make-possible-to-test-replacements-with-options.patch @@ -0,0 +1,71 @@ +From 0831393dd08d5f9dcf2e0517dbb4ea546ff7156b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 7 Sep 2022 15:21:52 +0200 +Subject: [PATCH] tests/regex: Make possible to test replacements with options + +--- + glib/tests/regex.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/glib/tests/regex.c b/glib/tests/regex.c +index 291c21b4c7..26844d63a7 100644 +--- a/glib/tests/regex.c ++++ b/glib/tests/regex.c +@@ -1207,6 +1207,8 @@ typedef struct { + gint start_position; + const gchar *replacement; + const gchar *expected; ++ GRegexCompileFlags compile_flags; ++ GRegexMatchFlags match_flags; + } TestReplaceData; + + static void +@@ -1215,17 +1217,25 @@ test_replace (gconstpointer d) + const TestReplaceData *data = d; + GRegex *regex; + gchar *res; ++ GError *error = NULL; + +- regex = g_regex_new (data->pattern, G_REGEX_DEFAULT, G_REGEX_MATCH_DEFAULT, NULL); +- res = g_regex_replace (regex, data->string, -1, data->start_position, data->replacement, 0, NULL); ++ regex = g_regex_new (data->pattern, data->compile_flags, G_REGEX_MATCH_DEFAULT, &error); ++ g_assert_no_error (error); ++ ++ res = g_regex_replace (regex, data->string, -1, data->start_position, ++ data->replacement, data->match_flags, &error); + + g_assert_cmpstr (res, ==, data->expected); + ++ if (data->expected) ++ g_assert_no_error (error); ++ + g_free (res); + g_regex_unref (regex); ++ g_clear_error (&error); + } + +-#define TEST_REPLACE(_pattern, _string, _start_position, _replacement, _expected) { \ ++#define TEST_REPLACE_OPTIONS(_pattern, _string, _start_position, _replacement, _expected, _compile_flags, _match_flags) { \ + TestReplaceData *data; \ + gchar *path; \ + data = g_new0 (TestReplaceData, 1); \ +@@ -1234,11 +1244,16 @@ test_replace (gconstpointer d) + data->start_position = _start_position; \ + data->replacement = _replacement; \ + data->expected = _expected; \ ++ data->compile_flags = _compile_flags; \ ++ data->match_flags = _match_flags; \ + path = g_strdup_printf ("/regex/replace/%d", ++total); \ + g_test_add_data_func_full (path, data, test_replace, g_free); \ + g_free (path); \ + } + ++#define TEST_REPLACE(_pattern, _string, _start_position, _replacement, _expected) \ ++ TEST_REPLACE_OPTIONS (_pattern, _string, _start_position, _replacement, _expected, 0, 0) ++ + static void + test_replace_lit (gconstpointer d) + { +-- +GitLab + diff --git a/backport-regex-Perform-more-tests-both-with-and-without-optimizations.patch b/backport-regex-Perform-more-tests-both-with-and-without-optimizations.patch new file mode 100644 index 0000000000000000000000000000000000000000..135e07602397c38d54023dfc1471f9a93fb33b1a --- /dev/null +++ b/backport-regex-Perform-more-tests-both-with-and-without-optimizations.patch @@ -0,0 +1,188 @@ +From 653f8eb0203485c7ffb0eeae81e6e30437d18529 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 9 Sep 2022 18:43:47 +0200 +Subject: [PATCH] tests/regex: Perform more tests both with and without + optimizations + +--- + glib/tests/regex.c | 101 +++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 93 insertions(+), 8 deletions(-) + +diff --git a/glib/tests/regex.c b/glib/tests/regex.c +index 2052ba0204..9803d49659 100644 +--- a/glib/tests/regex.c ++++ b/glib/tests/regex.c +@@ -173,7 +173,24 @@ test_match_simple (gconstpointer d) + data->compile_opts = _compile_opts; \ + data->match_opts = _match_opts; \ + data->expected = _expected; \ +- path = g_strdup_printf ("/regex/match-%s/%d", _name, ++total); \ ++ total++; \ ++ if (data->compile_opts & G_REGEX_OPTIMIZE) \ ++ path = g_strdup_printf ("/regex/match-%s-optimized/%d", _name, total); \ ++ else \ ++ path = g_strdup_printf ("/regex/match-%s/%d", _name, total); \ ++ g_test_add_data_func_full (path, data, test_match_simple, g_free); \ ++ g_free (path); \ ++ data = g_memdup2 (data, sizeof (TestMatchData)); \ ++ if (data->compile_opts & G_REGEX_OPTIMIZE) \ ++ { \ ++ data->compile_opts &= ~G_REGEX_OPTIMIZE; \ ++ path = g_strdup_printf ("/regex/match-%s/%d", _name, total); \ ++ } \ ++ else \ ++ { \ ++ data->compile_opts |= G_REGEX_OPTIMIZE; \ ++ path = g_strdup_printf ("/regex/match-%s-optimized/%d", _name, total); \ ++ } \ + g_test_add_data_func_full (path, data, test_match_simple, g_free); \ + g_free (path); \ + } +@@ -361,7 +378,24 @@ test_match (gconstpointer d) + data->start_position = _start_position; \ + data->match_opts2 = _match_opts2; \ + data->expected = _expected; \ +- path = g_strdup_printf ("/regex/match/%d", ++total); \ ++ total++; \ ++ if (data->compile_opts & G_REGEX_OPTIMIZE) \ ++ path = g_strdup_printf ("/regex/match-optimized/%d", total); \ ++ else \ ++ path = g_strdup_printf ("/regex/match/%d", total); \ ++ g_test_add_data_func_full (path, data, test_match, g_free); \ ++ g_free (path); \ ++ data = g_memdup2 (data, sizeof (TestMatchData)); \ ++ if (data->compile_opts & G_REGEX_OPTIMIZE) \ ++ { \ ++ data->compile_opts &= ~G_REGEX_OPTIMIZE; \ ++ path = g_strdup_printf ("/regex/match/%d", total); \ ++ } \ ++ else \ ++ { \ ++ data->compile_opts |= G_REGEX_OPTIMIZE; \ ++ path = g_strdup_printf ("/regex/match-optimized/%d", total); \ ++ } \ + g_test_add_data_func_full (path, data, test_match, g_free); \ + g_free (path); \ + } +@@ -580,6 +614,7 @@ typedef struct { + const gchar *pattern; + const gchar *string; + gint start_position; ++ GRegexCompileFlags compile_flags; + GRegexMatchFlags match_opts; + gint expected_count; + } TestMatchCountData; +@@ -592,7 +627,8 @@ test_match_count (gconstpointer d) + GMatchInfo *match_info; + gint count; + +- regex = g_regex_new (data->pattern, G_REGEX_DEFAULT, G_REGEX_MATCH_DEFAULT, NULL); ++ regex = g_regex_new (data->pattern, data->compile_flags, ++ G_REGEX_MATCH_DEFAULT, NULL); + + g_assert (regex != NULL); + +@@ -617,7 +653,14 @@ test_match_count (gconstpointer d) + data->start_position = _start_position; \ + data->match_opts = _match_opts; \ + data->expected_count = _expected_count; \ +- path = g_strdup_printf ("/regex/match/count/%d", ++total); \ ++ data->compile_flags = G_REGEX_DEFAULT; \ ++ total++; \ ++ path = g_strdup_printf ("/regex/match/count/%d", total); \ ++ g_test_add_data_func_full (path, data, test_match_count, g_free); \ ++ g_free (path); \ ++ data = g_memdup2 (data, sizeof (TestMatchCountData)); \ ++ data->compile_flags |= G_REGEX_OPTIMIZE; \ ++ path = g_strdup_printf ("/regex/match/count-optimized/%d", total); \ + g_test_add_data_func_full (path, data, test_match_count, g_free); \ + g_free (path); \ + } +@@ -656,7 +699,24 @@ test_partial (gconstpointer d) + data->compile_opts = _compile_opts; \ + data->match_opts = _match_opts; \ + data->expected = _expected; \ +- path = g_strdup_printf ("/regex/match/partial/%d", ++total); \ ++ total++; \ ++ if (data->compile_opts & G_REGEX_OPTIMIZE) \ ++ path = g_strdup_printf ("/regex/match/partial-optimized/%d", total); \ ++ else \ ++ path = g_strdup_printf ("/regex/match/partial%d", total); \ ++ g_test_add_data_func_full (path, data, test_partial, g_free); \ ++ g_free (path); \ ++ data = g_memdup2 (data, sizeof (TestMatchData)); \ ++ if (data->compile_opts & G_REGEX_OPTIMIZE) \ ++ { \ ++ data->compile_opts &= ~G_REGEX_OPTIMIZE; \ ++ path = g_strdup_printf ("/regex/match/partial%d", total); \ ++ } \ ++ else \ ++ { \ ++ data->compile_opts |= G_REGEX_OPTIMIZE; \ ++ path = g_strdup_printf ("/regex/match/partial-optimized/%d", total); \ ++ } \ + g_test_add_data_func_full (path, data, test_partial, g_free); \ + g_free (path); \ + } +@@ -666,6 +726,7 @@ test_partial (gconstpointer d) + typedef struct { + const gchar *pattern; + const gchar *string; ++ GRegexCompileFlags compile_flags; + gint start_position; + gint sub_n; + const gchar *expected_sub; +@@ -682,7 +743,7 @@ test_sub_pattern (gconstpointer d) + gchar *sub_expr; + gint start = UNTOUCHED, end = UNTOUCHED; + +- regex = g_regex_new (data->pattern, G_REGEX_DEFAULT, G_REGEX_MATCH_DEFAULT, NULL); ++ regex = g_regex_new (data->pattern, data->compile_flags, G_REGEX_MATCH_DEFAULT, NULL); + + g_assert (regex != NULL); + +@@ -712,7 +773,14 @@ test_sub_pattern (gconstpointer d) + data->expected_sub = _expected_sub; \ + data->expected_start = _expected_start; \ + data->expected_end = _expected_end; \ +- path = g_strdup_printf ("/regex/match/subpattern/%d", ++total); \ ++ data->compile_flags = G_REGEX_DEFAULT; \ ++ total++; \ ++ path = g_strdup_printf ("/regex/match/subpattern/%d", total); \ ++ g_test_add_data_func_full (path, data, test_sub_pattern, g_free); \ ++ g_free (path); \ ++ data = g_memdup2 (data, sizeof (TestSubData)); \ ++ data->compile_flags = G_REGEX_OPTIMIZE; \ ++ path = g_strdup_printf ("/regex/match/subpattern-optimized/%d", total); \ + g_test_add_data_func_full (path, data, test_sub_pattern, g_free); \ + g_free (path); \ + } +@@ -1246,7 +1314,24 @@ test_replace (gconstpointer d) + data->expected = _expected; \ + data->compile_flags = _compile_flags; \ + data->match_flags = _match_flags; \ +- path = g_strdup_printf ("/regex/replace/%d", ++total); \ ++ total++; \ ++ if (data->compile_flags & G_REGEX_OPTIMIZE) \ ++ path = g_strdup_printf ("/regex/replace-optimized/%d", total); \ ++ else \ ++ path = g_strdup_printf ("/regex/replace/%d", total); \ ++ g_test_add_data_func_full (path, data, test_replace, g_free); \ ++ g_free (path); \ ++ data = g_memdup2 (data, sizeof (TestReplaceData)); \ ++ if (data->compile_flags & G_REGEX_OPTIMIZE) \ ++ { \ ++ data->compile_flags &= ~G_REGEX_OPTIMIZE; \ ++ path = g_strdup_printf ("/regex/replace/%d", total); \ ++ } \ ++ else \ ++ { \ ++ data->compile_flags |= G_REGEX_OPTIMIZE; \ ++ path = g_strdup_printf ("/regex/replace-optimized/%d", total); \ ++ } \ + g_test_add_data_func_full (path, data, test_replace, g_free); \ + g_free (path); \ + } +-- +GitLab + diff --git a/backport-regex-Use-size-types-more-in-line-with-PCRE2-returned-values.patch b/backport-regex-Use-size-types-more-in-line-with-PCRE2-returned-values.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ad0033e9c956ff05543038175cbdaa1c5fee024 --- /dev/null +++ b/backport-regex-Use-size-types-more-in-line-with-PCRE2-returned-values.patch @@ -0,0 +1,148 @@ +From 1d628dac92283d75f7c751ddad72c28f4a7afe39 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 6 Sep 2022 18:21:52 +0200 +Subject: [PATCH] regex: Use size types more in line with PCRE2 returned values + +We're using int for every size value while PCRE uses uint_32t or +PCRE2_SIZE (size_t in most platforms), let's use the same types to avoid +using different signs. +--- + glib/gregex.c | 34 +++++++++++++++++++--------------- + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/glib/gregex.c b/glib/gregex.c +index 6f3ee88122..b886b24e2a 100644 +--- a/glib/gregex.c ++++ b/glib/gregex.c +@@ -23,6 +23,7 @@ + + #include "config.h" + ++#include + #include + + #define PCRE2_CODE_UNIT_WIDTH 8 +@@ -226,12 +227,12 @@ struct _GMatchInfo + GRegex *regex; /* the regex */ + uint32_t match_opts; /* pcre match options used at match time on the regex */ + gint matches; /* number of matching sub patterns, guaranteed to be <= (n_subpatterns + 1) if doing a single match (rather than matching all) */ +- gint n_subpatterns; /* total number of sub patterns in the regex */ ++ uint32_t n_subpatterns; /* total number of sub patterns in the regex */ + gint pos; /* position in the string where last match left off */ +- gint n_offsets; /* number of offsets */ ++ uint32_t n_offsets; /* number of offsets */ + gint *offsets; /* array of offsets paired 0,1 ; 2,3 ; 3,4 etc */ + gint *workspace; /* workspace for pcre2_dfa_match() */ +- gint n_workspace; /* number of workspace elements */ ++ PCRE2_SIZE n_workspace; /* number of workspace elements */ + const gchar *string; /* string passed to the match function */ + gssize string_len; /* length of string, in bytes */ + pcre2_match_context *match_context; +@@ -254,7 +255,7 @@ struct _GRegex + GRegexCompileFlags orig_compile_opts; /* options used at compile time on the pattern, gregex values */ + uint32_t match_opts; /* pcre2 options used at match time on the regex */ + GRegexMatchFlags orig_match_opts; /* options used as default match options, gregex values */ +- gint jit_options; /* options which were enabled for jit compiler */ ++ uint32_t jit_options; /* options which were enabled for jit compiler */ + JITStatus jit_status; /* indicates the status of jit compiler for this compiled regex */ + }; + +@@ -831,9 +832,9 @@ recalc_match_offsets (GMatchInfo *match_info, + GError **error) + { + PCRE2_SIZE *ovector; +- gint i; ++ uint32_t i; + +- if (pcre2_get_ovector_count (match_info->match_data) > G_MAXINT / 2) ++ if (pcre2_get_ovector_count (match_info->match_data) > G_MAXUINT32 / 2) + { + g_set_error (error, G_REGEX_ERROR, G_REGEX_ERROR_MATCH, + _("Error while matching regular expression %s: %s"), +@@ -858,7 +859,8 @@ static void + enable_jit_with_match_options (GRegex *regex, + uint32_t match_options) + { +- gint old_jit_options, new_jit_options, retval; ++ gint retval; ++ uint32_t old_jit_options, new_jit_options; + + if (!(regex->orig_compile_opts & G_REGEX_OPTIMIZE)) + return; +@@ -1104,7 +1106,8 @@ g_match_info_next (GMatchInfo *match_info, + match_info->pos = match_info->offsets[1]; + } + +- g_assert (match_info->matches <= match_info->n_subpatterns + 1); ++ g_assert (match_info->matches < 0 || ++ (uint32_t) match_info->matches <= match_info->n_subpatterns + 1); + + /* it's possible to get two identical matches when we are matching + * empty strings, for instance if the pattern is "(?=[A-Z0-9])" and +@@ -1387,7 +1390,7 @@ g_match_info_fetch_pos (const GMatchInfo *match_info, + /* make sure the sub expression number they're requesting is less than + * the total number of sub expressions in the regex. When matching all + * (g_regex_match_all()), also compare against the number of matches */ +- if (match_num >= MAX (match_info->n_subpatterns + 1, match_info->matches)) ++ if ((uint32_t) match_num >= MAX (match_info->n_subpatterns + 1, (uint32_t) match_info->matches)) + return FALSE; + + if (start_pos != NULL) +@@ -1797,7 +1800,7 @@ get_pcre2_inline_compile_options (pcre2_code *re, + + if (!(compile_options & PCRE2_DUPNAMES)) + { +- gboolean jchanged = FALSE; ++ uint32_t jchanged = 0; + pcre2_pattern_info (re, PCRE2_INFO_JCHANGED, &jchanged); + if (jchanged) + compile_options |= PCRE2_DUPNAMES; +@@ -1840,7 +1843,7 @@ g_regex_get_pattern (const GRegex *regex) + gint + g_regex_get_max_backref (const GRegex *regex) + { +- gint value; ++ uint32_t value; + + pcre2_pattern_info (regex->pcre_re, PCRE2_INFO_BACKREFMAX, &value); + +@@ -1860,7 +1863,7 @@ g_regex_get_max_backref (const GRegex *regex) + gint + g_regex_get_capture_count (const GRegex *regex) + { +- gint value; ++ uint32_t value; + + pcre2_pattern_info (regex->pcre_re, PCRE2_INFO_CAPTURECOUNT, &value); + +@@ -1880,7 +1883,7 @@ g_regex_get_capture_count (const GRegex *regex) + gboolean + g_regex_get_has_cr_or_lf (const GRegex *regex) + { +- gint value; ++ uint32_t value; + + pcre2_pattern_info (regex->pcre_re, PCRE2_INFO_HASCRORLF, &value); + +@@ -1902,7 +1905,7 @@ g_regex_get_has_cr_or_lf (const GRegex *regex) + gint + g_regex_get_max_lookbehind (const GRegex *regex) + { +- gint max_lookbehind; ++ uint32_t max_lookbehind; + + pcre2_pattern_info (regex->pcre_re, PCRE2_INFO_MAXLOOKBEHIND, + &max_lookbehind); +@@ -1927,7 +1930,8 @@ g_regex_get_max_lookbehind (const GRegex *regex) + GRegexCompileFlags + g_regex_get_compile_flags (const GRegex *regex) + { +- gint extra_flags, info_value; ++ GRegexCompileFlags extra_flags; ++ uint32_t info_value; + + g_return_val_if_fail (regex != NULL, 0); + +-- +GitLab + diff --git a/backport-tests-dbus-appinfo-Add-test-case-for-flatpak-opening-an-invalid-file.patch b/backport-tests-dbus-appinfo-Add-test-case-for-flatpak-opening-an-invalid-file.patch new file mode 100644 index 0000000000000000000000000000000000000000..b82fc7f37d783367304eac95c97980e0a1e09d29 --- /dev/null +++ b/backport-tests-dbus-appinfo-Add-test-case-for-flatpak-opening-an-invalid-file.patch @@ -0,0 +1,119 @@ +From 511627b7356af527c85c049e2020a36694d7de54 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 2 Sep 2022 18:56:35 +0200 +Subject: [PATCH] tests/dbus-appinfo: Add test case for flatpak opening an + invalid file + +We were testing the case in which we were opening an actual file, and so +potentially using a fd-list, however we were missing the case in which a file +was not existent. + +And in such case we are incidentally hitting a leak now. + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/511627b7356af527c85c049e2020a36694d7de54 + +--- + gio/tests/dbus-appinfo.c | 79 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 79 insertions(+) + +diff --git a/gio/tests/dbus-appinfo.c b/gio/tests/dbus-appinfo.c +index 2017e02df2..91e76403c6 100644 +--- a/gio/tests/dbus-appinfo.c ++++ b/gio/tests/dbus-appinfo.c +@@ -360,6 +360,84 @@ test_flatpak_doc_export (void) + g_object_unref (flatpak_appinfo); + } + ++static void ++on_flatpak_launch_invalid_uri_finish (GObject *object, ++ GAsyncResult *result, ++ gpointer user_data) ++{ ++ GApplication *app = user_data; ++ GError *error = NULL; ++ ++ g_app_info_launch_uris_finish (G_APP_INFO (object), result, &error); ++ g_assert_no_error (error); ++ ++ g_application_release (app); ++} ++ ++static void ++on_flatpak_activate_invalid_uri (GApplication *app, ++ gpointer user_data) ++{ ++ GDesktopAppInfo *flatpak_appinfo = user_data; ++ GList *uris; ++ ++ /* The app will be released in on_flatpak_launch_uris_finish */ ++ g_application_hold (app); ++ ++ uris = g_list_prepend (NULL, "file:///hopefully/an/invalid/path.desktop"); ++ g_app_info_launch_uris_async (G_APP_INFO (flatpak_appinfo), uris, NULL, ++ NULL, on_flatpak_launch_invalid_uri_finish, app); ++ g_list_free (uris); ++} ++ ++static void ++on_flatpak_open_invalid_uri (GApplication *app, ++ GFile **files, ++ gint n_files, ++ const char *hint) ++{ ++ GFile *f; ++ ++ g_assert_cmpint (n_files, ==, 1); ++ g_test_message ("on_flatpak_open received file '%s'", g_file_peek_path (files[0])); ++ ++ /* The file has been exported via the document portal */ ++ f = g_file_new_for_uri ("file:///hopefully/an/invalid/path.desktop"); ++ g_assert_true (g_file_equal (files[0], f)); ++ g_object_unref (f); ++} ++ ++static void ++test_flatpak_missing_doc_export (void) ++{ ++ const gchar *argv[] = { "myapp", NULL }; ++ gchar *desktop_file = NULL; ++ GDesktopAppInfo *flatpak_appinfo; ++ GApplication *app; ++ int status; ++ ++ g_test_summary ("Test that files launched via Flatpak apps are made available via the document portal."); ++ ++ desktop_file = g_test_build_filename (G_TEST_DIST, ++ "org.gtk.test.dbusappinfo.flatpak.desktop", ++ NULL); ++ flatpak_appinfo = g_desktop_app_info_new_from_filename (desktop_file); ++ g_assert_nonnull (flatpak_appinfo); ++ ++ app = g_application_new ("org.gtk.test.dbusappinfo.flatpak", ++ G_APPLICATION_HANDLES_OPEN); ++ g_signal_connect (app, "activate", G_CALLBACK (on_flatpak_activate_invalid_uri), ++ flatpak_appinfo); ++ g_signal_connect (app, "open", G_CALLBACK (on_flatpak_open_invalid_uri), NULL); ++ ++ status = g_application_run (app, 1, (gchar **) argv); ++ g_assert_cmpint (status, ==, 0); ++ ++ g_object_unref (app); ++ g_object_unref (flatpak_appinfo); ++ g_free (desktop_file); ++} ++ + int + main (int argc, char **argv) + { +@@ -367,6 +445,7 @@ main (int argc, char **argv) + + g_test_add_func ("/appinfo/dbusappinfo", test_dbus_appinfo); + g_test_add_func ("/appinfo/flatpak-doc-export", test_flatpak_doc_export); ++ g_test_add_func ("/appinfo/flatpak-missing-doc-export", test_flatpak_missing_doc_export); + + return session_bus_run (); + } +-- +GitLab + diff --git a/backport-xdgmime-fix-double-free.patch b/backport-xdgmime-fix-double-free.patch new file mode 100644 index 0000000000000000000000000000000000000000..8aa6991fb30c94662c71b5f7a99dc6dd7af74446 --- /dev/null +++ b/backport-xdgmime-fix-double-free.patch @@ -0,0 +1,36 @@ +From f95ca6cb713383548f16f9a8ba2f6c51a4d25e25 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Fri, 17 Jun 2022 08:48:10 -0500 +Subject: [PATCH] xdgmime: fix double free + +We free xdg_dirs[i] twice, but fail to free xdg_dirs itself. + +Also, since free() is NULL-safe, there is no need for the second check +here. + +Discovered in: https://gitlab.freedesktop.org/xdg/xdgmime/-/merge_requests/16#note_1432025 + +Conflict:NA +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/f95ca6cb713383548f16f9a8ba2f6c51a4d25e25 + +--- + gio/xdgmime/xdgmime.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/gio/xdgmime/xdgmime.c b/gio/xdgmime/xdgmime.c +index 9ab6760486..c3c11625e8 100644 +--- a/gio/xdgmime/xdgmime.c ++++ b/gio/xdgmime/xdgmime.c +@@ -350,8 +350,7 @@ xdg_mime_set_dirs (const char * const *dirs) + + for (i = 0; xdg_dirs != NULL && xdg_dirs[i] != NULL; i++) + free (xdg_dirs[i]); +- if (xdg_dirs != NULL) +- free (xdg_dirs[i]); ++ free (xdg_dirs); + xdg_dirs = NULL; + + if (dirs != NULL) +-- +GitLab + diff --git a/glib2.spec b/glib2.spec index 73dbccf181584b1ee9cc35e07b6f0bbb654f45f0..4cd535e04aa937e4d25167d6b4c9809a80e45480 100644 --- a/glib2.spec +++ b/glib2.spec @@ -1,6 +1,6 @@ Name: glib2 Version: 2.72.2 -Release: 3 +Release: 4 Summary: The core library that forms the basis for projects such as GTK+ and GNOME License: LGPLv2+ URL: http://www.gtk.org @@ -24,6 +24,34 @@ Patch6014: backport-gregex-use-g_debug-instead-of-g_warning-in-case-JIT-is- Patch6015: backport-gregex-do-not-set-match-and-recursion-limits-on-match-context.patch Patch6016: backport-gregex-add-original-test-case.patch Patch6017: backport-gregex-use-correct-size-for-pcre2_pattern_info.patch +Patch6018: backport-regex-Add-debug-strings-for-compile-and-match-option-flags.patch +Patch6019: backport-regex-Actually-check-for-match-options-changes.patch +Patch6020: backport-regex-Do-not-mix-PCRE2-Compile-Match-Newline-and-BSR-flags.patch +Patch6021: backport-regex-Add-test-for-gtksourceview-regression.patch +Patch6022: backport-gregex-Mark-g_match_info_get_regex-as-transfer-none.patch +Patch6023: backport-gregex-Do-not-try-access-the-undefined-match-offsets.patch +Patch6024: backport-gregex-Fix-a-potential-PCRE2-code-leak-on-reallocation-failures.patch +Patch6025: backport-regex-Use-size-types-more-in-line-with-PCRE2-returned-values.patch +Patch6026: backport-gregex-Handle-the-case-we-need-to-re-allocate-the-match-data.patch +Patch6027: backport-gregex-Avoid-re-allocating-if-we-have-no-size-change.patch +Patch6028: backport-regex-Compute-the-offsets-size-based-on-match-results.patch +Patch6029: backport-regex-Avoid-allocating-offsets-until-we-ve-a-match.patch +Patch6030: backport-regex-Handle-JIT-errors-more-explicitly.patch +Patch6031: backport-regex-Make-possible-to-test-replacements-with-options.patch +Patch6032: backport-regex-Do-not-use-JIT-when-using-unsupported-match-options.patch +Patch6033: backport-regex-Perform-more-tests-both-with-and-without-optimizations.patch +Patch6034: backport-gsocketclient-Fix-still-reachable-references-to-cancellables.patch +Patch6035: backport-Add-lock-in-_g_get_unix_mount_points-around-fsent-functions.patch +Patch6036: backport-g_get_unix_mount_points-reduce-syscalls-inside-loop.patch +Patch6037: backport-xdgmime-fix-double-free.patch +Patch6038: backport-Implement-GFileIface.set_display_name-for-resource-files.patch +Patch6039: backport-tests-dbus-appinfo-Add-test-case-for-flatpak-opening-an-invalid-file.patch +Patch6040: backport-documentportal-Fix-small-leak-in-add_documents-with-empty-URI-list.patch +Patch6041: backport-gio-tests-gdbus-proxy-threads-Unref-GVariant-s-that-we-own.patch +Patch6042: backport-gio-tests-gdbus-peer-Unref-cached-property-GVariant-value.patch +Patch6043: backport-gdesktopappinfo-Unref-the-GDBus-call-results.patch +Patch6044: backport-Handling-collision-between-standard-i-o-file-descriptors-and-newly-created-ones.patch +Patch6045: backport-glocalfileoutputstream-Do-not-double-close-an-fd-on-unlink-error.patch BuildRequires: chrpath gcc gcc-c++ gettext perl-interpreter BUildRequires: glibc-devel libattr-devel libselinux-devel meson @@ -197,6 +225,9 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : %endif %changelog +* Sat Oct 15 2022 hanhuihui - 2.72.2-4 +- backport some patches from community + * Mon Sep 5 2022 hanhuihui - 2.72.2-3 - replace pcre1 with pcre2