]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
charset: make strchr_m/strrchr_m/strstr_m const-correct via C11 _Generic
authorAndreas Schneider <asn@samba.org>
Wed, 22 Apr 2026 17:05:29 +0000 (19:05 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 21 May 2026 17:25:33 +0000 (17:25 +0000)
Since glibc-2.43 and C23, strchr/strrchr/strstr use _Generic macros to
return const char * when given const char * input. This caused build
failures in strchr_m and strrchr_m whose fast-path returns passed the
const char * result through as char *:

  lib/util/charset/util_str.c:370: error: return discards 'const'
  qualifier from pointer target type [-Werror=discarded-qualifiers]

Rather than wrapping the returns in discard_const_p (which the project
discourages adding more of), fix the API properly: rename the
implementations to strchr_m_const/strrchr_m_const/strstr_m_const
returning const char *, and expose C11 _Generic macros under the
original names. The macros preserve the caller's const qualification:
char * input yields char *, const char * input yields const char *.
This matches C23 strchr semantics and requires no changes at call sites.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=16006

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
lib/util/charset/charset.h
lib/util/charset/util_str.c

index ab91c0abd433ee6ad4b10e132c4db9f9fd2277ce..d73c79211540cf8c8110e58486c5974a0520b80d 100644 (file)
@@ -133,7 +133,6 @@ unsigned char *talloc_utf16_strlendup(TALLOC_CTX *mem_ctx, const char *str, size
 unsigned char *talloc_utf16_strdup(TALLOC_CTX *mem_ctx, const char *str);
 unsigned char *talloc_utf16_strndup(TALLOC_CTX *mem_ctx, const char *str, size_t n);
 
-char *strchr_m(const char *s, char c);
 /**
  * Calculate the number of units (8 or 16-bit, depending on the
  * destination charset) that would be needed to convert the input
@@ -184,9 +183,27 @@ bool strhaslower_handle(struct smb_iconv_handle *ic,
 bool strhaslower(const char *string);
 bool strhasupper_handle(struct smb_iconv_handle *ic,
                        const char *string);
-char *strrchr_m(const char *s, char c);
-char *strchr_m(const char *s, char c);
-char *strstr_m(const char *src, const char *findstr);
+const char *strchr_m_const(const char *s, char c);
+const char *strrchr_m_const(const char *s, char c);
+const char *strstr_m_const(const char *src, const char *findstr);
+char *strchr_m_nonconst(const char *s, char c);
+char *strrchr_m_nonconst(const char *s, char c);
+char *strstr_m_nonconst(const char *s, const char *findstr);
+
+#define strchr_m(s, c) _Generic((s), \
+       char *:       strchr_m_nonconst((s), (c)), \
+       const char *: strchr_m_const((s), (c)), \
+       default:      strchr_m_nonconst((s), (c)))
+
+#define strrchr_m(s, c) _Generic((s), \
+       char *:       strrchr_m_nonconst((s), (c)), \
+       const char *: strrchr_m_const((s), (c)), \
+       default:      strrchr_m_nonconst((s), (c)))
+
+#define strstr_m(s, f) _Generic((s), \
+       char *:       strstr_m_nonconst((s), (f)), \
+       const char *: strstr_m_const((s), (f)), \
+       default:      strstr_m_nonconst((s), (f)))
 
 bool utf8_check(const char *input, size_t maxlen,
                size_t *byte_len,
index 4c243e6976af8a5371d62b52d5254bab0f0421cb..c214cb1a796955545391bf2a17e9e8bde98e41b2 100644 (file)
@@ -357,7 +357,7 @@ _PUBLIC_ size_t strlen_m_term_null(const char *s)
 /**
  Strchr and strrchr_m are a bit complex on general multi-byte strings.
 **/
-_PUBLIC_ char *strchr_m(const char *src, char c)
+_PUBLIC_ const char *strchr_m_const(const char *src, char c)
 {
        const char *s;
        struct smb_iconv_handle *ic = NULL;
@@ -377,7 +377,7 @@ _PUBLIC_ char *strchr_m(const char *src, char c)
 
        for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) {
                if (*s == c)
-                       return discard_const_p(char, s);
+                       return s;
        }
 
        if (!*s)
@@ -394,7 +394,7 @@ _PUBLIC_ char *strchr_m(const char *src, char c)
                size_t size;
                codepoint_t c2 = next_codepoint_handle(ic, s, &size);
                if (c2 == c) {
-                       return discard_const_p(char, s);
+                       return s;
                }
                s += size;
        }
@@ -405,10 +405,10 @@ _PUBLIC_ char *strchr_m(const char *src, char c)
 /**
  * Multibyte-character version of strrchr
  */
-_PUBLIC_ char *strrchr_m(const char *s, char c)
+_PUBLIC_ const char *strrchr_m_const(const char *s, char c)
 {
        struct smb_iconv_handle *ic;
-       char *ret = NULL;
+       const char *ret = NULL;
 
        if (s == NULL) {
                return NULL;
@@ -447,7 +447,7 @@ _PUBLIC_ char *strrchr_m(const char *s, char c)
                                        break;
                                }
                                /* No - we have a match ! */
-                               return discard_const_p(char , cp);
+                               return cp;
                        }
                } while (cp-- != s);
                if (!got_mb)
@@ -460,7 +460,7 @@ _PUBLIC_ char *strrchr_m(const char *s, char c)
                size_t size;
                codepoint_t c2 = next_codepoint_handle(ic, s, &size);
                if (c2 == c) {
-                       ret = discard_const_p(char, s);
+                       ret = s;
                }
                s += size;
        }
@@ -468,6 +468,21 @@ _PUBLIC_ char *strrchr_m(const char *s, char c)
        return ret;
 }
 
+_PUBLIC_ char *strchr_m_nonconst(const char *s, char c)
+{
+       return discard_const_p(char, strchr_m_const(s, c));
+}
+
+_PUBLIC_ char *strrchr_m_nonconst(const char *s, char c)
+{
+       return discard_const_p(char, strrchr_m_const(s, c));
+}
+
+_PUBLIC_ char *strstr_m_nonconst(const char *s, const char *findstr)
+{
+       return discard_const_p(char, strstr_m_const(s, findstr));
+}
+
 /**
   return True if any (multi-byte) character is lower case
 */
@@ -532,24 +547,24 @@ _PUBLIC_ bool strhasupper(const char *string)
  strstr_m - We convert via ucs2 for now.
 ***********************************************************************/
 
-char *strstr_m(const char *src, const char *findstr)
+_PUBLIC_ const char *strstr_m_const(const char *src, const char *findstr)
 {
        TALLOC_CTX *mem_ctx = NULL;
        smb_ucs2_t *p;
        smb_ucs2_t *src_w, *find_w;
        const char *s;
        char *s2;
-       char *retp = NULL;
+       const char *retp = NULL;
        size_t converted_size, findstr_len = 0;
 
        /* for correctness */
        if (!findstr[0]) {
-               return discard_const_p(char, src);
+               return src;
        }
 
        /* Samba does single character findstr calls a *lot*. */
        if (findstr[1] == '\0')
-               return strchr_m(src, *findstr);
+               return strchr_m_const(src, *findstr);
 
        /* We optimise for the ascii case, knowing that all our
           supported multi-byte character sets are ascii-compatible
@@ -561,7 +576,7 @@ char *strstr_m(const char *src, const char *findstr)
                                findstr_len = strlen(findstr);
 
                        if (strncmp(s, findstr, findstr_len) == 0) {
-                               return discard_const_p(char, s);
+                               return s;
                        }
                }
        }
@@ -604,7 +619,7 @@ char *strstr_m(const char *src, const char *findstr)
        if (!pull_ucs2_talloc(mem_ctx, &s2, src_w, &converted_size)) {
                goto done;
        }
-       retp = discard_const_p(char, (s+strlen(s2)));
+       retp = s + strlen(s2);
 done:
        TALLOC_FREE(mem_ctx);
        return retp;