gnu: libsoup: Apply patches fixing deadlocks and CVE-2025-4476.

The patches are a subset taken from Debian (see:
<https://sources.debian.org/patches/libsoup3/3.6.5-3/>).

* gnu/packages/patches/libsoup-auth-digest-fix-crash.patch
* gnu/packages/patches/libsoup-deadlock-in-add_listener_in_thread.patch
* gnu/packages/patches/libsoup-fix-merge-of-ranges.patch
* gnu/packages/patches/libsoup-memory-leak-in-soup_form_decode.patch
* gnu/packages/patches/libsoup-multipart-bounds-check.patch
* gnu/packages/patches/libsoup-use-libdl-instead-of-gmodule.patch: New files.
* gnu/local.mk (dist_patch_DATA): Register them.
* gnu/packages/gnome.scm (libsoup-minimal): Apply them.

Change-Id: I7e4968c1d87e28860fc68616f6107d018e0d93dd
This commit is contained in:
Maxim Cournoyer 2025-07-31 08:02:12 +09:00 committed by Liliana Marie Prikler
parent 5a9f1de9af
commit 111d7e518e
No known key found for this signature in database
GPG key ID: 442A84B8C70E2F87
8 changed files with 561 additions and 5 deletions

View file

@ -1799,6 +1799,12 @@ dist_patch_DATA = \
%D%/packages/patches/libsecret-fix-test-paths.patch \
%D%/packages/patches/libsepol-versioned-docbook.patch \
%D%/packages/patches/libskk-fix-invalid-escape.patch \
%D%/packages/patches/libsoup-auth-digest-fix-crash.patch \
%D%/packages/patches/libsoup-deadlock-in-add_listener_in_thread.patch \
%D%/packages/patches/libsoup-fix-merge-of-ranges.patch \
%D%/packages/patches/libsoup-memory-leak-in-soup_form_decode.patch \
%D%/packages/patches/libsoup-multipart-bounds-check.patch \
%D%/packages/patches/libsoup-use-libdl-instead-of-gmodule.patch \
%D%/packages/patches/libspatialite-libxml2-2.14.patch \
%D%/packages/patches/libtar-CVE-2013-4420.patch \
%D%/packages/patches/libtar-CVE-2021-33643-CVE-2021-33644.patch \

View file

@ -5104,7 +5104,15 @@ as OpenStreetMap, OpenCycleMap, OpenAerialMap and Maps.")
"libsoup-" version ".tar.xz"))
(sha256
(base32
"0d52mnvvsvwpc3scjva5fbvns8f8ijyswgjwjhbr151ymid7d4b8"))))
"0d52mnvvsvwpc3scjva5fbvns8f8ijyswgjwjhbr151ymid7d4b8"))
(patches
(search-patches
"libsoup-auth-digest-fix-crash.patch"
"libsoup-deadlock-in-add_listener_in_thread.patch"
"libsoup-fix-merge-of-ranges.patch"
"libsoup-memory-leak-in-soup_form_decode.patch"
"libsoup-multipart-bounds-check.patch"
"libsoup-use-libdl-instead-of-gmodule.patch"))))
(build-system meson-build-system)
(arguments
(list
@ -5128,21 +5136,21 @@ as OpenStreetMap, OpenCycleMap, OpenAerialMap and Maps.")
(substitute* "tests/hsts-db-test.c"
((".*/hsts-db/subdomains.*") "")))))))
(native-inputs
(list `(,glib "bin") ;for glib-mkenums
(list `(,glib "bin") ;for glib-mkenums
gobject-introspection
pkg-config
python-wrapper
vala
curl
gnutls ;for 'certtool'
gnutls ;for 'certtool'
httpd/pinned))
(propagated-inputs
;; libsoup-3.0.pc refers to all of these (except where otherwise noted)
(list brotli
glib
glib-networking ; for GIO runtime modules
glib-networking ; for GIO runtime modules
libpsl
nghttp2 ;for pkg-config
nghttp2 ;for pkg-config
`(,nghttp2 "lib")
libxml2
mit-krb5

View file

@ -0,0 +1,31 @@
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Thu, 8 May 2025 09:27:01 -0500
Subject: auth-digest: fix crash in soup_auth_digest_get_protection_space()
We need to validate the Domain parameter in the WWW-Authenticate header.
Unfortunately this crash only occurs when listening on default ports 80
and 443, so there's no good way to test for this. The test would require
running as root.
Origin: upstream, 3.7.0, commit:e64c221f9c7d09b48b610c5626b3b8c400f0907c
Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/440
Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2025-4476
Bug-Debian: https://bugs.debian.org/1105887
---
libsoup/auth/soup-auth-digest.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libsoup/auth/soup-auth-digest.c b/libsoup/auth/soup-auth-digest.c
index d8bb291..292f204 100644
--- a/libsoup/auth/soup-auth-digest.c
+++ b/libsoup/auth/soup-auth-digest.c
@@ -220,7 +220,7 @@ soup_auth_digest_get_protection_space (SoupAuth *auth, GUri *source_uri)
if (uri &&
g_strcmp0 (g_uri_get_scheme (uri), g_uri_get_scheme (source_uri)) == 0 &&
g_uri_get_port (uri) == g_uri_get_port (source_uri) &&
- !strcmp (g_uri_get_host (uri), g_uri_get_host (source_uri)))
+ !g_strcmp0 (g_uri_get_host (uri), g_uri_get_host (source_uri)))
dir = g_strdup (g_uri_get_path (uri));
else
dir = NULL;

View file

@ -0,0 +1,42 @@
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Wed, 30 Apr 2025 14:13:41 -0500
Subject: test-utils: fix deadlock in add_listener_in_thread()
The mutex is locked in the wrong place here.
Hopefully fixes #379
Origin: upstream, 3.7.0, commit:3c0cee2cfddb9ba31b30421f2b3cdd3c5a255e99
Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/379
---
tests/test-utils.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/tests/test-utils.c b/tests/test-utils.c
index 62f0b83..6fb09b6 100644
--- a/tests/test-utils.c
+++ b/tests/test-utils.c
@@ -627,9 +627,11 @@ static gboolean
add_listener_in_thread (gpointer user_data)
{
AddListenerData *data = user_data;
+ GUri *uri;
- data->uri = add_listener (data->server, data->scheme, data->host);
+ uri = add_listener (data->server, data->scheme, data->host);
g_mutex_lock (&data->mutex);
+ data->uri = uri;
g_cond_signal (&data->cond);
g_mutex_unlock (&data->mutex);
@@ -661,9 +663,9 @@ soup_test_server_get_uri (SoupServer *server,
data.host = host;
data.uri = NULL;
- g_mutex_lock (&data.mutex);
soup_add_completion (context, add_listener_in_thread, &data);
+ g_mutex_lock (&data.mutex);
while (!data.uri)
g_cond_wait (&data.cond, &data.mutex);

View file

@ -0,0 +1,192 @@
From: Milan Crha <mcrha@redhat.com>
Date: Tue, 15 Apr 2025 12:17:39 +0200
Subject: soup-message-headers: Correct merge of ranges
It had been skipping every second range, which generated an array
of a lot of insane ranges, causing large memory usage by the server.
Origin: upstream, 3.7.0, commit:9bb92f7a685e31e10e9e8221d0342280432ce836
Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/428
Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2025-32907
Bug-Debian: https://bugs.debian.org/1103264
---
libsoup/soup-message-headers.c | 1 +
tests/meson.build | 1 +
tests/server-mem-limit-test.c | 144 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 146 insertions(+)
create mode 100644 tests/server-mem-limit-test.c
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index ee7a3cb..f101d4b 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -1244,6 +1244,7 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs,
if (cur->start <= prev->end) {
prev->end = MAX (prev->end, cur->end);
g_array_remove_index (array, i);
+ i--;
}
}
}
diff --git a/tests/meson.build b/tests/meson.build
index cf4ddbd..68e6d01 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -102,6 +102,7 @@ tests = [
{'name': 'samesite'},
{'name': 'session'},
{'name': 'server-auth'},
+ {'name': 'server-mem-limit'},
{'name': 'server'},
{'name': 'sniffing',
'depends': [test_resources],
diff --git a/tests/server-mem-limit-test.c b/tests/server-mem-limit-test.c
new file mode 100644
index 0000000..98f1c40
--- /dev/null
+++ b/tests/server-mem-limit-test.c
@@ -0,0 +1,144 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2025 Red Hat <www.redhat.com>
+ */
+
+#include "test-utils.h"
+
+#include <sys/resource.h>
+
+/*
+ This test limits memory usage to trigger too large buffer allocation crash.
+ As restoring the limits back to what it was does not always work, it's split
+ out of the server-test.c test with copied minimal server code.
+ */
+
+typedef struct {
+ SoupServer *server;
+ GUri *base_uri, *ssl_base_uri;
+ GSList *handlers;
+} ServerData;
+
+static void
+server_setup_nohandler (ServerData *sd, gconstpointer test_data)
+{
+ sd->server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
+ sd->base_uri = soup_test_server_get_uri (sd->server, "http", NULL);
+ if (tls_available)
+ sd->ssl_base_uri = soup_test_server_get_uri (sd->server, "https", NULL);
+}
+
+static void
+server_add_handler (ServerData *sd,
+ const char *path,
+ SoupServerCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy)
+{
+ soup_server_add_handler (sd->server, path, callback, user_data, destroy);
+ sd->handlers = g_slist_prepend (sd->handlers, g_strdup (path));
+}
+
+static void
+server_setup (ServerData *sd, gconstpointer test_data)
+{
+ server_setup_nohandler (sd, test_data);
+}
+
+static void
+server_teardown (ServerData *sd, gconstpointer test_data)
+{
+ GSList *iter;
+
+ for (iter = sd->handlers; iter; iter = iter->next)
+ soup_server_remove_handler (sd->server, iter->data);
+ g_slist_free_full (sd->handlers, g_free);
+
+ g_clear_pointer (&sd->server, soup_test_server_quit_unref);
+ g_clear_pointer (&sd->base_uri, g_uri_unref);
+ g_clear_pointer (&sd->ssl_base_uri, g_uri_unref);
+}
+
+static void
+server_file_callback (SoupServer *server,
+ SoupServerMessage *msg,
+ const char *path,
+ GHashTable *query,
+ gpointer data)
+{
+ void *mem;
+
+ g_assert_cmpstr (path, ==, "/file");
+ g_assert_cmpstr (soup_server_message_get_method (msg), ==, SOUP_METHOD_GET);
+
+ mem = g_malloc0 (sizeof (char) * 1024 * 1024);
+ /* fedora-scan CI claims a warning about possibly leaked `mem` variable, thus use
+ the copy and free it explicitly, to workaround the false positive; the g_steal_pointer()
+ did not help for the malloc-ed memory */
+ soup_server_message_set_response (msg, "application/octet-stream", SOUP_MEMORY_COPY, mem, sizeof (char) * 1024 *1024);
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
+ g_free (mem);
+}
+
+static void
+do_ranges_overlaps_test (ServerData *sd, gconstpointer test_data)
+{
+ SoupSession *session;
+ SoupMessage *msg;
+ GString *range;
+ GUri *uri;
+ const char *chunk = ",0,0,0,0,0,0,0,0,0,0,0";
+
+ g_test_bug ("428");
+
+ #ifdef G_OS_WIN32
+ g_test_skip ("Cannot run under windows");
+ return;
+ #endif
+
+ range = g_string_sized_new (99 * 1024);
+ g_string_append (range, "bytes=1024");
+ while (range->len < 99 * 1024)
+ g_string_append (range, chunk);
+
+ session = soup_test_session_new (NULL);
+ server_add_handler (sd, "/file", server_file_callback, NULL, NULL);
+
+ uri = g_uri_parse_relative (sd->base_uri, "/file", SOUP_HTTP_URI_FLAGS, NULL);
+
+ msg = soup_message_new_from_uri ("GET", uri);
+ soup_message_headers_append (soup_message_get_request_headers (msg), "Range", range->str);
+
+ soup_test_session_send_message (session, msg);
+
+ soup_test_assert_message_status (msg, SOUP_STATUS_PARTIAL_CONTENT);
+
+ g_object_unref (msg);
+
+ g_string_free (range, TRUE);
+ g_uri_unref (uri);
+
+ soup_test_session_abort_unref (session);
+}
+
+int
+main (int argc, char **argv)
+{
+ int ret;
+
+ test_init (argc, argv, NULL);
+
+ #ifndef G_OS_WIN32
+ struct rlimit new_rlimit = { 1024 * 1024 * 64, 1024 * 1024 * 64 };
+ /* limit memory usage, to trigger too large memory allocation abort */
+ g_assert_cmpint (setrlimit (RLIMIT_DATA, &new_rlimit), ==, 0);
+ #endif
+
+ g_test_add ("/server-mem/range-overlaps", ServerData, NULL,
+ server_setup, do_ranges_overlaps_test, server_teardown);
+
+ ret = g_test_run ();
+
+ test_cleanup ();
+ return ret;
+}

View file

@ -0,0 +1,101 @@
From: Milan Crha <mcrha@redhat.com>
Date: Tue, 13 May 2025 10:38:49 +0200
Subject: soup-form: Fix a possible memory leak in
soup_form_decode_multipart()
The output variables can be set multiple times, when there are multiparts
with the same name, thus first clear any previously value and only then
assign a new value.
Origin: upstream, 3.7.0, commit:66b5c5be947062df9caf7025b56ee1de32aee3ac
Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/446
---
libsoup/soup-form.c | 12 +++++++++---
tests/forms-test.c | 41 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+), 3 deletions(-)
diff --git a/libsoup/soup-form.c b/libsoup/soup-form.c
index 2eb5d57..98130c8 100644
--- a/libsoup/soup-form.c
+++ b/libsoup/soup-form.c
@@ -168,12 +168,18 @@ soup_form_decode_multipart (SoupMultipart *multipart,
}
if (file_control_name && !strcmp (name, file_control_name)) {
- if (filename)
+ if (filename) {
+ g_free (*filename);
*filename = g_strdup (g_hash_table_lookup (params, "filename"));
- if (content_type)
+ }
+ if (content_type) {
+ g_free (*content_type);
*content_type = g_strdup (soup_message_headers_get_content_type (part_headers, NULL));
- if (file)
+ }
+ if (file) {
+ g_clear_pointer (file, g_bytes_unref);
*file = g_bytes_ref (part_body);
+ }
} else {
g_hash_table_insert (form_data_set,
g_strdup (name),
diff --git a/tests/forms-test.c b/tests/forms-test.c
index 1002374..183900f 100644
--- a/tests/forms-test.c
+++ b/tests/forms-test.c
@@ -485,6 +485,46 @@ md5_callback (SoupServer *server,
soup_server_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED, NULL);
}
+static void
+do_form_decode_multipart_test (void)
+{
+ SoupMultipart *multipart = soup_multipart_new ("multipart/form-data");
+ const char *file_control_name = "uploaded_file";
+ char *content_type = NULL;
+ char *filename = NULL;
+ GBytes *file = NULL;
+ GHashTable *result;
+ int part;
+
+ for (part = 0; part < 2; part++) {
+ SoupMessageHeaders *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
+ GHashTable *params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ GBytes *body = g_bytes_new (NULL, 0);
+
+ g_hash_table_insert (params, g_strdup ("name"), g_strdup (file_control_name));
+ g_hash_table_insert (params, g_strdup ("filename"), g_strdup (file_control_name));
+ soup_message_headers_set_content_disposition (headers, "form-data", params);
+ soup_message_headers_set_content_type (headers, "text/x-form", NULL);
+ soup_multipart_append_part (multipart, headers, body);
+
+ soup_message_headers_unref (headers);
+ g_hash_table_destroy (params);
+ g_bytes_unref (body);
+ }
+
+ /* this would leak memory of the output variables, due to two parts having the same 'file_control_name' */
+ result = soup_form_decode_multipart (multipart, file_control_name, &filename, &content_type, &file);
+ g_assert_nonnull (result);
+ g_assert_cmpstr (content_type, ==, "text/x-form");
+ g_assert_cmpstr (filename, ==, file_control_name);
+ g_assert_nonnull (file);
+
+ g_hash_table_destroy (result);
+ g_free (content_type);
+ g_free (filename);
+ g_bytes_unref (file);
+}
+
static gboolean run_tests = TRUE;
static GOptionEntry no_test_entry[] = {
@@ -525,6 +565,7 @@ main (int argc, char **argv)
g_uri_unref (uri);
g_test_add_func ("/forms/decode", do_form_decode_test);
+ g_test_add_func ("/forms/decodemultipart", do_form_decode_multipart_test);
ret = g_test_run ();
} else {

View file

@ -0,0 +1,106 @@
From: Milan Crha <mcrha@redhat.com>
Date: Tue, 15 Apr 2025 09:03:00 +0200
Subject: multipart: Fix read out of buffer bounds under
soup_multipart_new_from_message()
This is CVE-2025-32914, special crafted input can cause read out of buffer bounds
of the body argument.
Origin: upstream, 3.7.0, commit:5bfcf8157597f2d327050114fb37ff600004dbcf
Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/436
Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2025-32914
Bug-Debian: https://bugs.debian.org/1103267
---
libsoup/soup-multipart.c | 2 +-
tests/multipart-test.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+), 1 deletion(-)
diff --git a/libsoup/soup-multipart.c b/libsoup/soup-multipart.c
index 2421c91..102ce37 100644
--- a/libsoup/soup-multipart.c
+++ b/libsoup/soup-multipart.c
@@ -173,7 +173,7 @@ soup_multipart_new_from_message (SoupMessageHeaders *headers,
return NULL;
}
- split = strstr (start, "\r\n\r\n");
+ split = g_strstr_len (start, body_end - start, "\r\n\r\n");
if (!split || split > end) {
soup_multipart_free (multipart);
return NULL;
diff --git a/tests/multipart-test.c b/tests/multipart-test.c
index 2c0e7e9..f5b9868 100644
--- a/tests/multipart-test.c
+++ b/tests/multipart-test.c
@@ -471,6 +471,62 @@ test_multipart (gconstpointer data)
loop = NULL;
}
+static void
+test_multipart_bounds_good (void)
+{
+ #define TEXT "line1\r\nline2"
+ SoupMultipart *multipart;
+ SoupMessageHeaders *headers, *set_headers = NULL;
+ GBytes *bytes, *set_bytes = NULL;
+ const char *raw_data = "--123\r\nContent-Type: text/plain;\r\n\r\n" TEXT "\r\n--123--\r\n";
+ gboolean success;
+
+ headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
+ soup_message_headers_append (headers, "Content-Type", "multipart/mixed; boundary=\"123\"");
+
+ bytes = g_bytes_new (raw_data, strlen (raw_data));
+
+ multipart = soup_multipart_new_from_message (headers, bytes);
+
+ g_assert_nonnull (multipart);
+ g_assert_cmpint (soup_multipart_get_length (multipart), ==, 1);
+ success = soup_multipart_get_part (multipart, 0, &set_headers, &set_bytes);
+ g_assert_true (success);
+ g_assert_nonnull (set_headers);
+ g_assert_nonnull (set_bytes);
+ g_assert_cmpint (strlen (TEXT), ==, g_bytes_get_size (set_bytes));
+ g_assert_cmpstr ("text/plain", ==, soup_message_headers_get_content_type (set_headers, NULL));
+ g_assert_cmpmem (TEXT, strlen (TEXT), g_bytes_get_data (set_bytes, NULL), g_bytes_get_size (set_bytes));
+
+ soup_message_headers_unref (headers);
+ g_bytes_unref (bytes);
+
+ soup_multipart_free (multipart);
+
+ #undef TEXT
+}
+
+static void
+test_multipart_bounds_bad (void)
+{
+ SoupMultipart *multipart;
+ SoupMessageHeaders *headers;
+ GBytes *bytes;
+ const char *raw_data = "--123\r\nContent-Type: text/plain;\r\nline1\r\nline2\r\n--123--\r\n";
+
+ headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
+ soup_message_headers_append (headers, "Content-Type", "multipart/mixed; boundary=\"123\"");
+
+ bytes = g_bytes_new (raw_data, strlen (raw_data));
+
+ /* it did read out of raw_data/bytes bounds */
+ multipart = soup_multipart_new_from_message (headers, bytes);
+ g_assert_null (multipart);
+
+ soup_message_headers_unref (headers);
+ g_bytes_unref (bytes);
+}
+
int
main (int argc, char **argv)
{
@@ -498,6 +554,8 @@ main (int argc, char **argv)
g_test_add_data_func ("/multipart/sync", GINT_TO_POINTER (SYNC_MULTIPART), test_multipart);
g_test_add_data_func ("/multipart/async", GINT_TO_POINTER (ASYNC_MULTIPART), test_multipart);
g_test_add_data_func ("/multipart/async-small-reads", GINT_TO_POINTER (ASYNC_MULTIPART_SMALL_READS), test_multipart);
+ g_test_add_func ("/multipart/bounds-good", test_multipart_bounds_good);
+ g_test_add_func ("/multipart/bounds-bad", test_multipart_bounds_bad);
ret = g_test_run ();

View file

@ -0,0 +1,70 @@
From: Fabio Manganiello <fabio@manganiello.tech>
Date: Tue, 15 Jul 2025 15:41:47 +0200
Subject: soup-init: Use libdl instead of gmodule in `soup2_is_loaded` check
Calling `g_module_open` in the library constructor can cause deadlocks
when libsoup is used with other libraries that also contend for GLib
mutexes. `dlopen` should be used instead.
Co-authored-by: Nirbheek Chauhan <nirbheek@centricular.com>
Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/463
Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/1443
Bug-Debian: https://bugs.debian.org/1109685
Origin: https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/475
Applied-upstream: 3.7.0, commit:1296cbf983f036f20262c453926dff77e1d6a852
Applied-upstream: 3.6.6, commit:2316e56a5502ac4c41ef4ff56a3266e680aca129
---
libsoup/soup-init.c | 28 +++++++++++++++++-----------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/libsoup/soup-init.c b/libsoup/soup-init.c
index 8a33c77..3392e8e 100644
--- a/libsoup/soup-init.c
+++ b/libsoup/soup-init.c
@@ -10,7 +10,6 @@
#endif
#include <glib/gi18n-lib.h>
-#include <gmodule.h>
#include "gconstructor.h"
#ifdef G_OS_WIN32
@@ -18,21 +17,28 @@
#include <windows.h>
HMODULE soup_dll;
+#else
+#include <dlfcn.h>
#endif
static gboolean
soup2_is_loaded (void)
{
- GModule *module = g_module_open (NULL, 0);
- gpointer func;
- gboolean result = FALSE;
-
- if (g_module_symbol (module, "soup_uri_new", &func))
- result = TRUE;
-
- g_module_close (module);
-
- return result;
+ gboolean result = FALSE;
+
+ /* Skip on PE/COFF, as it doesn't have a flat symbol namespace */
+#ifndef G_OS_WIN32
+ gpointer handle;
+ gpointer func;
+
+ handle = dlopen (NULL, RTLD_LAZY | RTLD_GLOBAL);
+ if (handle != NULL) {
+ func = dlsym (handle, "soup_uri_new");
+ result = (func != NULL);
+ dlclose (handle);
+ }
+#endif
+ return result;
}
static void