From a07961cfbed092f7e0388b367096b7e5fc364540 Mon Sep 17 00:00:00 2001 From: Jan Vaclav Date: Tue, 2 Dec 2025 11:05:08 +0100 Subject: [PATCH] systemd: selectively backport "Fix constness issues with newer glibc" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NetworkManager is failing to build on Rawhide with the following errors: ../src/libnm-systemd-shared/src/basic/string-util.h:33:16: error: return discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers] 33 | return strstr(haystack, needle); | ^~~~~~ In file included from ../src/libnm-systemd-shared/src/basic/fd-util.c:30: ../src/libnm-systemd-shared/src/basic/sort-util.h: In function ‘bsearch_safe’: ../src/libnm-systemd-shared/src/basic/sort-util.h:34:16: error: return discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers] 34 | return bsearch(key, base, nmemb, size, compar); | ^~~~~~~ This is fixed in systemd by commit 0bac1ed2422f15308414dd1e9d09812a966b0348: > Latest glibc uses _Generic to have strstr() and other functions return > const char* or char* based on whether the input is a const char* or a > char*. This causes build failures as we previously always expected a char*. > > Let's fix the compilation failures and add our own macros similar to glibc's > to have string functions that return a mutable or const pointer depending on > the input. Selectively backport the changes we need to fix building. --- src/libnm-systemd-shared/src/basic/sort-util.h | 7 +++++-- .../src/basic/string-util.c | 4 ++-- .../src/basic/string-util.h | 18 ++++++++++++------ .../src/fundamental/macro-fundamental.h | 9 ++++++++- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/libnm-systemd-shared/src/basic/sort-util.h b/src/libnm-systemd-shared/src/basic/sort-util.h index 9c818bd747..a3bfb32c1d 100644 --- a/src/libnm-systemd-shared/src/basic/sort-util.h +++ b/src/libnm-systemd-shared/src/basic/sort-util.h @@ -25,15 +25,18 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, * Normal bsearch requires base to be nonnull. Here were require * that only if nmemb > 0. */ -static inline void* bsearch_safe(const void *key, const void *base, +static inline void* bsearch_safe_internal(const void *key, const void *base, size_t nmemb, size_t size, comparison_fn_t compar) { if (nmemb <= 0) return NULL; assert(base); - return bsearch(key, base, nmemb, size, compar); + return (void*) bsearch(key, base, nmemb, size, compar); } +#define bsearch_safe(key, base, nmemb, size, compar) \ + const_generic((base), bsearch_safe_internal(key, base, nmemb, size, compar)) + #define typesafe_bsearch(k, b, n, func) \ ({ \ const typeof((b)[0]) *_k = k; \ diff --git a/src/libnm-systemd-shared/src/basic/string-util.c b/src/libnm-systemd-shared/src/basic/string-util.c index 5efd11eabc..52160fe3e2 100644 --- a/src/libnm-systemd-shared/src/basic/string-util.c +++ b/src/libnm-systemd-shared/src/basic/string-util.c @@ -1470,7 +1470,7 @@ ssize_t strlevenshtein(const char *x, const char *y) { return t1[yl]; } -char* strrstr(const char *haystack, const char *needle) { +char* strrstr_internal(const char *haystack, const char *needle) { /* Like strstr() but returns the last rather than the first occurrence of "needle" in "haystack". */ if (!haystack || !needle) @@ -1479,7 +1479,7 @@ char* strrstr(const char *haystack, const char *needle) { /* Special case: for the empty string we return the very last possible occurrence, i.e. *after* the * last char, not before. */ if (*needle == 0) - return strchr(haystack, 0); + return (char*) strchr(haystack, 0); for (const char *p = strstr(haystack, needle), *q; p; p = q) { q = strstr(p + 1, needle); diff --git a/src/libnm-systemd-shared/src/basic/string-util.h b/src/libnm-systemd-shared/src/basic/string-util.h index 91e63c9b12..5d2b5dfb16 100644 --- a/src/libnm-systemd-shared/src/basic/string-util.h +++ b/src/libnm-systemd-shared/src/basic/string-util.h @@ -27,24 +27,28 @@ #define URI_UNRESERVED ALPHANUMERICAL "-._~" /* [RFC3986] */ #define URI_VALID URI_RESERVED URI_UNRESERVED /* [RFC3986] */ -static inline char* strstr_ptr(const char *haystack, const char *needle) { +static inline char* strstr_ptr_internal(const char *haystack, const char *needle) { if (!haystack || !needle) return NULL; - return strstr(haystack, needle); + return (char*) strstr(haystack, needle); } -static inline char* strstrafter(const char *haystack, const char *needle) { - char *p; +#define strstr_ptr(haystack, needle) \ + const_generic(haystack, strstr_ptr_internal(haystack, needle)) +static inline char* strstrafter_internal(const char *haystack, const char *needle) { /* Returns NULL if not found, or pointer to first character after needle if found */ - p = strstr_ptr(haystack, needle); + char *p = (char*) strstr_ptr(haystack, needle); if (!p) return NULL; return p + strlen(needle); } +#define strstrafter(haystack, needle) \ + const_generic(haystack, strstrafter_internal(haystack, needle)) + static inline const char* strnull(const char *s) { return s ?: "(null)"; } @@ -300,6 +304,8 @@ bool version_is_valid_versionspec(const char *s); ssize_t strlevenshtein(const char *x, const char *y); -char* strrstr(const char *haystack, const char *needle); +char* strrstr_internal(const char *haystack, const char *needle); +#define strrstr(haystack, needle) \ + const_generic(haystack, strrstr_internal(haystack, needle)) size_t str_common_prefix(const char *a, const char *b); diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h index abdfb9b6bd..a89994e273 100644 --- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h +++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h @@ -511,4 +511,11 @@ assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1); #define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1]) #else /* NM_IGNORED */ #define PROJECT_FILE __FILE__ -#endif /* NM_IGNORED */ \ No newline at end of file +#endif /* NM_IGNORED */ + +/* This macro is used to have a const-returning and non-const returning version of a function based on + * whether its first argument is const or not (e.g. strstr()). */ +#define const_generic(ptr, call) \ + _Generic(0 ? (ptr) : (void*) 1, \ + const void*: (const typeof(*call)*) (call), \ + void*: (call))