Re: Fix some "call to function ... through pointer to incorrect function type" errors

Bruno Haible via Gnulib discussion list <[email protected]>
Newsgroups gmane.comp.lib.gnulib.bugs
Message-ID <7889650.ZlIXO0BPYK@cagnes>
Lasse Collin wrote:
> These sanitizer errors mean that the program cannot be compiled with
> strict forms of control flow integrity checking. It can be done in
> software (clang -flto -fsanitize=cfi -fvisibility=hidden)

Thanks for mentioning this; I did not know about this kind of sanitize
combined with optimization.

Indeed, I see a few test failures in the test cases, still (despite
the no_sanitize ("function") attributes). Fixing them through the attached
patch.

But some other test failures will remain:
  - jit/test-cache,
  - test-list-c++, test-map-c++, test-omap-c++, test-oset-c++.

The reason is that C is not only used for application programming —
for which the above options "-flto -fsanitize=cfi -fvisibility=hidden"
make sense [except for GNOME / Qt and their "signals"] — but also for
system programming, where treating functions of different prototypes
in the same way is commonplace (think of libffi or libffcall), or for
generics (where C++ programmers like to have 10 different code
instantiations for 10 different pointer types, but C programmers don't
like that).

Bruno


2026-08-15  Bruno Haible  <[email protected]>

	tests: Support CC="clang -flto -fsanitize=cfi -fvisibility=hidden".
	Reported by Lasse Collin in
	<https://lists.gnu.org/archive/html/bug-gnulib/2026-08/msg00190.html>.
	* tests/test-array_map.c (string_compare): New function.
	(main): Use instead of casting strcmp to a different function prototype.
	* tests/test-array_omap.c (string_compare): New function.
	(main): Use instead of casting strcmp to a different function prototype.
	* tests/test-avltree_omap.c (string_compare): New function.
	(main): Use instead of casting strcmp to a different function prototype.
	* tests/test-rbtree_omap.c (string_compare): New function.
	(main): Use instead of casting strcmp to a different function prototype.
	* tests/test-array_set.c (string_compare): New function.
	(main): Use instead of casting strcmp to a different function prototype.
	* tests/test-array_oset.c (string_compare): New function.
	(main): Use instead of casting strcmp to a different function prototype.
	* tests/test-avltree_oset.c (string_compare): New function.
	(main): Use instead of casting strcmp to a different function prototype.
	* tests/test-rbtree_oset.c (string_compare): New function.
	(main): Use instead of casting strcmp to a different function prototype.
	* tests/test-oset-update.h (test_update): Likewise.
0001-tests-Support-CC-clang-flto-fsanitize-cfi-fvisibilit.patch (text/x-patch, 19 KB)
From 9388edc18a2c1de1ae9f58cef2446e1c1116bf36 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 15 Aug 2026 17:46:48 +0200
Subject: [PATCH] tests: Support CC="clang -flto -fsanitize=cfi
 -fvisibility=hidden".

Reported by Lasse Collin in
<https://lists.gnu.org/archive/html/bug-gnulib/2026-08/msg00190.html>.

* tests/test-array_map.c (string_compare): New function.
(main): Use instead of casting strcmp to a different function prototype.
* tests/test-array_omap.c (string_compare): New function.
(main): Use instead of casting strcmp to a different function prototype.
* tests/test-avltree_omap.c (string_compare): New function.
(main): Use instead of casting strcmp to a different function prototype.
* tests/test-rbtree_omap.c (string_compare): New function.
(main): Use instead of casting strcmp to a different function prototype.
* tests/test-array_set.c (string_compare): New function.
(main): Use instead of casting strcmp to a different function prototype.
* tests/test-array_oset.c (string_compare): New function.
(main): Use instead of casting strcmp to a different function prototype.
* tests/test-avltree_oset.c (string_compare): New function.
(main): Use instead of casting strcmp to a different function prototype.
* tests/test-rbtree_oset.c (string_compare): New function.
(main): Use instead of casting strcmp to a different function prototype.
* tests/test-oset-update.h (test_update): Likewise.
---
 ChangeLog                 | 23 +++++++++++++++++++++++
 tests/test-array_map.c    | 24 ++++++++++++++++--------
 tests/test-array_omap.c   | 26 +++++++++++++++++---------
 tests/test-array_oset.c   | 26 +++++++++++++++++---------
 tests/test-array_set.c    | 10 +++++++++-
 tests/test-avltree_omap.c | 12 ++++++++++--
 tests/test-avltree_oset.c | 16 ++++++++++++----
 tests/test-oset-update.h  |  2 +-
 tests/test-rbtree_omap.c  | 12 ++++++++++--
 tests/test-rbtree_oset.c  | 16 ++++++++++++----
 10 files changed, 127 insertions(+), 40 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index f6b4603910..19acb732d8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2026-08-15  Bruno Haible  <[email protected]>
+
+	tests: Support CC="clang -flto -fsanitize=cfi -fvisibility=hidden".
+	Reported by Lasse Collin in
+	<https://lists.gnu.org/archive/html/bug-gnulib/2026-08/msg00190.html>.
+	* tests/test-array_map.c (string_compare): New function.
+	(main): Use instead of casting strcmp to a different function prototype.
+	* tests/test-array_omap.c (string_compare): New function.
+	(main): Use instead of casting strcmp to a different function prototype.
+	* tests/test-avltree_omap.c (string_compare): New function.
+	(main): Use instead of casting strcmp to a different function prototype.
+	* tests/test-rbtree_omap.c (string_compare): New function.
+	(main): Use instead of casting strcmp to a different function prototype.
+	* tests/test-array_set.c (string_compare): New function.
+	(main): Use instead of casting strcmp to a different function prototype.
+	* tests/test-array_oset.c (string_compare): New function.
+	(main): Use instead of casting strcmp to a different function prototype.
+	* tests/test-avltree_oset.c (string_compare): New function.
+	(main): Use instead of casting strcmp to a different function prototype.
+	* tests/test-rbtree_oset.c (string_compare): New function.
+	(main): Use instead of casting strcmp to a different function prototype.
+	* tests/test-oset-update.h (test_update): Likewise.
+
 2026-08-15  Bruno Haible  <[email protected]>
 
 	memmove: Avoid undefined behaviour upon memmove (NULL, ptr, 0).
diff --git a/tests/test-array_map.c b/tests/test-array_map.c
index 5e93d4b74c..265debd550 100644
--- a/tests/test-array_map.c
+++ b/tests/test-array_map.c
@@ -34,6 +34,14 @@ static const char *objects[30] =
     "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "<", ">", "[", "]"
   };
 
+static int
+string_compare (const void *elt1, const void *elt2)
+{
+  const char *s1 = elt1;
+  const char *s2 = elt2;
+  return strcmp (s1, s2);
+}
+
 static bool
 string_equals (const void *x1, const void *x2)
 {
@@ -143,12 +151,12 @@ main (int argc, char *argv[])
         const char *key = RANDOM_OBJECT ();
         const char *value = RANDOM_OBJECT ();
         bool added = gl_map_nx_put (map1, key, value);
-        size_t index = gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+        size_t index = gl_sortedlist_indexof (keys, string_compare, key);
         ASSERT (added == (index == (size_t)(-1)));
         if (added)
           {
-            gl_sortedlist_add (keys, (gl_listelement_compar_fn)strcmp, key);
-            index = gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+            gl_sortedlist_add (keys, string_compare, key);
+            index = gl_sortedlist_indexof (keys, string_compare, key);
             gl_list_add_at (values, index, value);
           }
         else
@@ -166,7 +174,7 @@ main (int argc, char *argv[])
               const char *key = RANDOM_OBJECT ();
               const void *ret = gl_map_get (map1, key);
               size_t index =
-                gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+                gl_sortedlist_indexof (keys, string_compare, key);
               ASSERT (ret
                       == (index != (size_t)(-1) ? gl_list_get_at (values, index) : NULL));
             }
@@ -177,12 +185,12 @@ main (int argc, char *argv[])
               const char *value = RANDOM_OBJECT ();
               bool added = gl_map_nx_put (map1, key, value);
               size_t index =
-                gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+                gl_sortedlist_indexof (keys, string_compare, key);
               ASSERT (added == (index == (size_t)(-1)));
               if (added)
                 {
-                  gl_sortedlist_add (keys, (gl_listelement_compar_fn)strcmp, key);
-                  index = gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+                  gl_sortedlist_add (keys, string_compare, key);
+                  index = gl_sortedlist_indexof (keys, string_compare, key);
                   gl_list_add_at (values, index, value);
                 }
               else
@@ -194,7 +202,7 @@ main (int argc, char *argv[])
               const char *key = RANDOM_OBJECT ();
               bool removed = gl_map_remove (map1, key);
               size_t index =
-                gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+                gl_sortedlist_indexof (keys, string_compare, key);
               ASSERT (removed == (index != (size_t)(-1)));
               if (removed)
                 {
diff --git a/tests/test-array_omap.c b/tests/test-array_omap.c
index 44c4e8d18e..b04ab30467 100644
--- a/tests/test-array_omap.c
+++ b/tests/test-array_omap.c
@@ -73,6 +73,14 @@ check_all (gl_omap_t map1, gl_list_t keys, gl_list_t values)
   check_equals (map1, keys, values);
 }
 
+static int
+string_compare (const void *elt1, const void *elt2)
+{
+  const char *s1 = elt1;
+  const char *s2 = elt2;
+  return strcmp (s1, s2);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -88,7 +96,7 @@ main (int argc, char *argv[])
     size_t initial_size = RANDOM (20);
 
     /* Create map1.  */
-    map1 = gl_omap_nx_create_empty (GL_ARRAY_OMAP, (gl_mapkey_compar_fn) strcmp, NULL, NULL);
+    map1 = gl_omap_nx_create_empty (GL_ARRAY_OMAP, string_compare, NULL, NULL);
     ASSERT (map1 != NULL);
 
     /* Create keys and values.  */
@@ -103,12 +111,12 @@ main (int argc, char *argv[])
         const char *key = RANDOM_OBJECT ();
         const char *value = RANDOM_OBJECT ();
         bool added = gl_omap_nx_put (map1, key, value);
-        size_t index = gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+        size_t index = gl_sortedlist_indexof (keys, string_compare, key);
         ASSERT (added == (index == (size_t)(-1)));
         if (added)
           {
-            gl_sortedlist_add (keys, (gl_listelement_compar_fn)strcmp, key);
-            index = gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+            gl_sortedlist_add (keys, string_compare, key);
+            index = gl_sortedlist_indexof (keys, string_compare, key);
             gl_list_add_at (values, index, value);
           }
         else
@@ -126,7 +134,7 @@ main (int argc, char *argv[])
               const char *key = RANDOM_OBJECT ();
               const void *ret = gl_omap_get (map1, key);
               size_t index =
-                gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+                gl_sortedlist_indexof (keys, string_compare, key);
               ASSERT (ret
                       == (index != (size_t)(-1) ? gl_list_get_at (values, index) : NULL));
             }
@@ -137,12 +145,12 @@ main (int argc, char *argv[])
               const char *value = RANDOM_OBJECT ();
               bool added = gl_omap_nx_put (map1, key, value);
               size_t index =
-                gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+                gl_sortedlist_indexof (keys, string_compare, key);
               ASSERT (added == (index == (size_t)(-1)));
               if (added)
                 {
-                  gl_sortedlist_add (keys, (gl_listelement_compar_fn)strcmp, key);
-                  index = gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+                  gl_sortedlist_add (keys, string_compare, key);
+                  index = gl_sortedlist_indexof (keys, string_compare, key);
                   gl_list_add_at (values, index, value);
                 }
               else
@@ -154,7 +162,7 @@ main (int argc, char *argv[])
               const char *key = RANDOM_OBJECT ();
               bool removed = gl_omap_remove (map1, key);
               size_t index =
-                gl_sortedlist_indexof (keys, (gl_listelement_compar_fn)strcmp, key);
+                gl_sortedlist_indexof (keys, string_compare, key);
               ASSERT (removed == (index != (size_t)(-1)));
               if (removed)
                 {
diff --git a/tests/test-array_oset.c b/tests/test-array_oset.c
index 59aae8be9c..99c095a2bb 100644
--- a/tests/test-array_oset.c
+++ b/tests/test-array_oset.c
@@ -27,8 +27,6 @@
 #include "gl_array_list.h"
 #include "macros.h"
 
-#include "test-oset-update.h"
-
 static const char *objects[30] =
   {
     "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
@@ -68,6 +66,14 @@ check_all (gl_oset_t set1, gl_list_t set2)
   check_equals (set1, set2);
 }
 
+static int
+string_compare (const void *elt1, const void *elt2)
+{
+  const char *s1 = elt1;
+  const char *s2 = elt2;
+  return strcmp (s1, s2);
+}
+
 static bool
 is_at_least (const void *elt, const void *threshold)
 {
@@ -88,6 +94,8 @@ gl_sortedlist_indexof_atleast (gl_list_t set,
   return (size_t)(-1);
 }
 
+#include "test-oset-update.h"
+
 int
 main (int argc, char *argv[])
 {
@@ -102,7 +110,7 @@ main (int argc, char *argv[])
     size_t initial_size = RANDOM (20);
 
     /* Create set1.  */
-    set1 = gl_oset_nx_create_empty (GL_ARRAY_OSET, (gl_setelement_compar_fn) strcmp, NULL);
+    set1 = gl_oset_nx_create_empty (GL_ARRAY_OSET, string_compare, NULL);
     ASSERT (set1 != NULL);
 
     /* Create set2.  */
@@ -115,9 +123,9 @@ main (int argc, char *argv[])
       {
         const char *obj = RANDOM_OBJECT ();
         ASSERT (gl_oset_nx_add (set1, obj)
-                == (gl_sortedlist_search (set2, (gl_listelement_compar_fn)strcmp, obj) != NULL
+                == (gl_sortedlist_search (set2, string_compare, obj) != NULL
                     ? false
-                    : (gl_sortedlist_add (set2, (gl_listelement_compar_fn)strcmp, obj), true)));
+                    : (gl_sortedlist_add (set2, string_compare, obj), true)));
         check_all (set1, set2);
       }
 
@@ -130,23 +138,23 @@ main (int argc, char *argv[])
             {
               const char *obj = RANDOM_OBJECT ();
               ASSERT (gl_oset_search (set1, obj)
-                      == (gl_sortedlist_search (set2, (gl_listelement_compar_fn)strcmp, obj) != NULL));
+                      == (gl_sortedlist_search (set2, string_compare, obj) != NULL));
             }
             break;
           case 1:
             {
               const char *obj = RANDOM_OBJECT ();
               ASSERT (gl_oset_nx_add (set1, obj)
-                      == (gl_sortedlist_search (set2, (gl_listelement_compar_fn)strcmp, obj) != NULL
+                      == (gl_sortedlist_search (set2, string_compare, obj) != NULL
                           ? false
-                          : (gl_sortedlist_add (set2, (gl_listelement_compar_fn)strcmp, obj), true)));
+                          : (gl_sortedlist_add (set2, string_compare, obj), true)));
             }
             break;
           case 2:
             {
               const char *obj = RANDOM_OBJECT ();
               ASSERT (gl_oset_remove (set1, obj)
-                      == gl_sortedlist_remove (set2, (gl_listelement_compar_fn)strcmp, obj));
+                      == gl_sortedlist_remove (set2, string_compare, obj));
             }
             break;
           case 3:
diff --git a/tests/test-array_set.c b/tests/test-array_set.c
index 4d18ecd1c7..1d02238fa7 100644
--- a/tests/test-array_set.c
+++ b/tests/test-array_set.c
@@ -88,6 +88,14 @@ check_all (gl_set_t set1, gl_oset_t set2)
   check_equals (set1, set2);
 }
 
+static int
+string_compare (const void *elt1, const void *elt2)
+{
+  const char *s1 = elt1;
+  const char *s2 = elt2;
+  return strcmp (s1, s2);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -106,7 +114,7 @@ main (int argc, char *argv[])
     ASSERT (set1 != NULL);
 
     /* Create set2.  */
-    set2 = gl_oset_create_empty (GL_ARRAY_OSET, (gl_setelement_compar_fn) strcmp, NULL);
+    set2 = gl_oset_create_empty (GL_ARRAY_OSET, string_compare, NULL);
 
     check_all (set1, set2);
 
diff --git a/tests/test-avltree_omap.c b/tests/test-avltree_omap.c
index d116971c4e..0a9bb3a616 100644
--- a/tests/test-avltree_omap.c
+++ b/tests/test-avltree_omap.c
@@ -69,6 +69,14 @@ check_all (gl_omap_t map1, gl_omap_t map2)
   check_equals (map1, map2);
 }
 
+static int
+string_compare (const void *key1, const void *key2)
+{
+  const char *s1 = key1;
+  const char *s2 = key2;
+  return strcmp (s1, s2);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -82,11 +90,11 @@ main (int argc, char *argv[])
     size_t initial_size = RANDOM (20);
 
     /* Create map1.  */
-    map1 = gl_omap_nx_create_empty (GL_ARRAY_OMAP, (gl_mapkey_compar_fn) strcmp, NULL, NULL);
+    map1 = gl_omap_nx_create_empty (GL_ARRAY_OMAP, string_compare, NULL, NULL);
     ASSERT (map1 != NULL);
 
     /* Create map2.  */
-    map2 = gl_omap_nx_create_empty (GL_AVLTREE_OMAP, (gl_mapkey_compar_fn) strcmp, NULL, NULL);
+    map2 = gl_omap_nx_create_empty (GL_AVLTREE_OMAP, string_compare, NULL, NULL);
     ASSERT (map2 != NULL);
 
     check_all (map1, map2);
diff --git a/tests/test-avltree_oset.c b/tests/test-avltree_oset.c
index 2a68aca332..9b1f2e32a1 100644
--- a/tests/test-avltree_oset.c
+++ b/tests/test-avltree_oset.c
@@ -26,8 +26,6 @@
 #include "gl_array_oset.h"
 #include "macros.h"
 
-#include "test-oset-update.h"
-
 extern void gl_avltree_oset_check_invariants (gl_oset_t set);
 
 static const char *objects[30] =
@@ -68,12 +66,22 @@ check_all (gl_oset_t set1, gl_oset_t set2)
   check_equals (set1, set2);
 }
 
+static int
+string_compare (const void *elt1, const void *elt2)
+{
+  const char *s1 = elt1;
+  const char *s2 = elt2;
+  return strcmp (s1, s2);
+}
+
 static bool
 is_at_least (const void *elt, const void *threshold)
 {
   return strcmp ((const char *) elt, (const char *) threshold) >= 0;
 }
 
+#include "test-oset-update.h"
+
 int
 main (int argc, char *argv[])
 {
@@ -87,11 +95,11 @@ main (int argc, char *argv[])
     size_t initial_size = RANDOM (20);
 
     /* Create set1.  */
-    set1 = gl_oset_nx_create_empty (GL_ARRAY_OSET, (gl_setelement_compar_fn) strcmp, NULL);
+    set1 = gl_oset_nx_create_empty (GL_ARRAY_OSET, string_compare, NULL);
     ASSERT (set1 != NULL);
 
     /* Create set2.  */
-    set2 = gl_oset_nx_create_empty (GL_AVLTREE_OSET, (gl_setelement_compar_fn) strcmp, NULL);
+    set2 = gl_oset_nx_create_empty (GL_AVLTREE_OSET, string_compare, NULL);
     ASSERT (set2 != NULL);
 
     check_all (set1, set2);
diff --git a/tests/test-oset-update.h b/tests/test-oset-update.h
index 973b6258a8..e301eb218e 100644
--- a/tests/test-oset-update.h
+++ b/tests/test-oset-update.h
@@ -30,7 +30,7 @@ test_update (gl_oset_implementation_t implementation)
   char D[2] = "D";
 
   gl_oset_t set1 =
-    gl_oset_nx_create_empty (implementation, (gl_setelement_compar_fn) strcmp, NULL);
+    gl_oset_nx_create_empty (implementation, string_compare, NULL);
   ASSERT (set1 != NULL);
 
   /* Fill the set.  */
diff --git a/tests/test-rbtree_omap.c b/tests/test-rbtree_omap.c
index 4d0781ca5e..777170fba8 100644
--- a/tests/test-rbtree_omap.c
+++ b/tests/test-rbtree_omap.c
@@ -69,6 +69,14 @@ check_all (gl_omap_t map1, gl_omap_t map2)
   check_equals (map1, map2);
 }
 
+static int
+string_compare (const void *key1, const void *key2)
+{
+  const char *s1 = key1;
+  const char *s2 = key2;
+  return strcmp (s1, s2);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -82,11 +90,11 @@ main (int argc, char *argv[])
     size_t initial_size = RANDOM (20);
 
     /* Create map1.  */
-    map1 = gl_omap_nx_create_empty (GL_ARRAY_OMAP, (gl_mapkey_compar_fn) strcmp, NULL, NULL);
+    map1 = gl_omap_nx_create_empty (GL_ARRAY_OMAP, string_compare, NULL, NULL);
     ASSERT (map1 != NULL);
 
     /* Create map2.  */
-    map2 = gl_omap_nx_create_empty (GL_RBTREE_OMAP, (gl_mapkey_compar_fn) strcmp, NULL, NULL);
+    map2 = gl_omap_nx_create_empty (GL_RBTREE_OMAP, string_compare, NULL, NULL);
     ASSERT (map2 != NULL);
 
     check_all (map1, map2);
diff --git a/tests/test-rbtree_oset.c b/tests/test-rbtree_oset.c
index 6edb6e72e1..385a216cd3 100644
--- a/tests/test-rbtree_oset.c
+++ b/tests/test-rbtree_oset.c
@@ -26,8 +26,6 @@
 #include "gl_array_oset.h"
 #include "macros.h"
 
-#include "test-oset-update.h"
-
 extern void gl_rbtree_oset_check_invariants (gl_oset_t set);
 
 static const char *objects[30] =
@@ -68,12 +66,22 @@ check_all (gl_oset_t set1, gl_oset_t set2)
   check_equals (set1, set2);
 }
 
+static int
+string_compare (const void *elt1, const void *elt2)
+{
+  const char *s1 = elt1;
+  const char *s2 = elt2;
+  return strcmp (s1, s2);
+}
+
 static bool
 is_at_least (const void *elt, const void *threshold)
 {
   return strcmp ((const char *) elt, (const char *) threshold) >= 0;
 }
 
+#include "test-oset-update.h"
+
 int
 main (int argc, char *argv[])
 {
@@ -87,11 +95,11 @@ main (int argc, char *argv[])
     size_t initial_size = RANDOM (20);
 
     /* Create set1.  */
-    set1 = gl_oset_nx_create_empty (GL_ARRAY_OSET, (gl_setelement_compar_fn) strcmp, NULL);
+    set1 = gl_oset_nx_create_empty (GL_ARRAY_OSET, string_compare, NULL);
     ASSERT (set1 != NULL);
 
     /* Create set2.  */
-    set2 = gl_oset_nx_create_empty (GL_RBTREE_OSET, (gl_setelement_compar_fn) strcmp, NULL);
+    set2 = gl_oset_nx_create_empty (GL_RBTREE_OSET, string_compare, NULL);
     ASSERT (set2 != NULL);
 
     check_all (set1, set2);
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.