systemd: selectively backport "Fix constness issues with newer glibc"

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.
This commit is contained in:
Jan Vaclav 2025-12-02 11:05:08 +01:00
parent 4e7e159224
commit a07961cfbe
4 changed files with 27 additions and 11 deletions

View file

@ -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 * Normal bsearch requires base to be nonnull. Here were require
* that only if nmemb > 0. * 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) { size_t nmemb, size_t size, comparison_fn_t compar) {
if (nmemb <= 0) if (nmemb <= 0)
return NULL; return NULL;
assert(base); 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) \ #define typesafe_bsearch(k, b, n, func) \
({ \ ({ \
const typeof((b)[0]) *_k = k; \ const typeof((b)[0]) *_k = k; \

View file

@ -1470,7 +1470,7 @@ ssize_t strlevenshtein(const char *x, const char *y) {
return t1[yl]; 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". */ /* Like strstr() but returns the last rather than the first occurrence of "needle" in "haystack". */
if (!haystack || !needle) 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 /* Special case: for the empty string we return the very last possible occurrence, i.e. *after* the
* last char, not before. */ * last char, not before. */
if (*needle == 0) if (*needle == 0)
return strchr(haystack, 0); return (char*) strchr(haystack, 0);
for (const char *p = strstr(haystack, needle), *q; p; p = q) { for (const char *p = strstr(haystack, needle), *q; p; p = q) {
q = strstr(p + 1, needle); q = strstr(p + 1, needle);

View file

@ -27,24 +27,28 @@
#define URI_UNRESERVED ALPHANUMERICAL "-._~" /* [RFC3986] */ #define URI_UNRESERVED ALPHANUMERICAL "-._~" /* [RFC3986] */
#define URI_VALID URI_RESERVED URI_UNRESERVED /* [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) if (!haystack || !needle)
return NULL; return NULL;
return strstr(haystack, needle); return (char*) strstr(haystack, needle);
} }
static inline char* strstrafter(const char *haystack, const char *needle) { #define strstr_ptr(haystack, needle) \
char *p; 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 */ /* 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) if (!p)
return NULL; return NULL;
return p + strlen(needle); return p + strlen(needle);
} }
#define strstrafter(haystack, needle) \
const_generic(haystack, strstrafter_internal(haystack, needle))
static inline const char* strnull(const char *s) { static inline const char* strnull(const char *s) {
return s ?: "(null)"; return s ?: "(null)";
} }
@ -300,6 +304,8 @@ bool version_is_valid_versionspec(const char *s);
ssize_t strlevenshtein(const char *x, const char *y); 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); size_t str_common_prefix(const char *a, const char *b);

View file

@ -512,3 +512,10 @@ assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1);
#else /* NM_IGNORED */ #else /* NM_IGNORED */
#define PROJECT_FILE __FILE__ #define PROJECT_FILE __FILE__
#endif /* NM_IGNORED */ #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))