From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 7118 invoked from network); 31 May 2023 14:01:08 -0000 Received: from second.openwall.net (193.110.157.125) by inbox.vuxu.org with ESMTPUTF8; 31 May 2023 14:01:08 -0000 Received: (qmail 30479 invoked by uid 550); 31 May 2023 14:00:55 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Reply-To: musl@lists.openwall.com Received: (qmail 30259 invoked from network); 31 May 2023 14:00:54 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inria.fr; s=dc; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=Ay+5IkCzwG1LbgFB3piJz2FjmW+2hcQfQhWQ4wKgpW8=; b=WtyoYU26iXcHUlPfCg9XWHZ1j33Wsh3Nx4v6YzuC+a343ek5jsj/xk1F G43zDpVor/hLzVA7sGmWsx9b6n1DDDeiJHlTP27fgzaZyap9JGZ2Odeo8 nf438nNERxWVmGXvL8juyT4jPekFwt9CfQeXHWNHhSug77z9KNTz2+0hv Q=; Authentication-Results: mail2-relais-roc.national.inria.fr; dkim=none (message not signed) header.i=none; spf=SoftFail smtp.mailfrom=Jens.Gustedt@inria.fr; dmarc=fail (p=none dis=none) d=inria.fr X-IronPort-AV: E=Sophos;i="6.00,207,1681164000"; d="scan'208";a="110510131" From: Jens Gustedt To: musl@lists.openwall.com Date: Wed, 31 May 2023 16:00:26 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [musl] [C23 const 2/2] C23: change string.h and wchar.h interfaces to macros that respects the const contract This adds a macro interfaces to those string functions that search for a string position. This has an additional cast of the return value to `void const*` for the case that the argument to the call was also const-qualified. Nothing changes for the correspondin function itself, only the identifier has to be protected with (), such that the macro does not expand for the function declaration or definition. The implementation of this macro might be a bit unusual for musl. It serves the purpose of better error tracking if users call the macro with the wrong argument. (0) Programming _Generic is hard. It needs that all choices are syntactically and semantically valid. Otherwise the users drowns in warnings and errors. (1) Compilers nowadays track on which line in a macro definition an error appears. For _Generic it helps a lot if the compiler presents the exact choice which leads to a diagnostic. (2) All object pointer values with unqualified or const-qualified target are valid for the memchr function. Therefore we use a trick that maps all const-qualified targets to void const*. (3) All other functions have to accept either pointers to character types (char or wchar_t) or pointers to void (where there is an implicit conversion to the character pointer). Therefore we cannot use the trick in (2), this would map any const-qualified pointer to that case. Instead, we list the two possible const-qualifed cases explicitly. (4) The case of wrongly qualified pointer arguments would lead to a misleading diagnostic without the casts. --- include/string.h | 54 ++++++++++++++++++++++++++++++++++++++----- include/wchar.h | 55 +++++++++++++++++++++++++++++++++++++++----- src/include/string.h | 6 +++++ src/include/wchar.h | 6 +++++ src/string/memchr.c | 2 +- src/string/strchr.c | 2 +- src/string/strpbrk.c | 2 +- src/string/strrchr.c | 2 +- src/string/strstr.c | 2 +- src/string/wcschr.c | 2 +- src/string/wcspbrk.c | 2 +- src/string/wcsrchr.c | 2 +- src/string/wcsstr.c | 2 +- src/string/wmemchr.c | 2 +- 14 files changed, 119 insertions(+), 22 deletions(-) diff --git a/include/string.h b/include/string.h index 7df7a402..61768cf7 100644 --- a/include/string.h +++ b/include/string.h @@ -28,7 +28,54 @@ void *memcpy (void *__restrict, const void *__restrict, size_t); void *memmove (void *, const void *, size_t); void *memset (void *, int, size_t); int memcmp (const void *, const void *, size_t); -void *memchr (const void *, int, size_t); + +void *(memchr) (const void *, int, size_t); +char *(strchr) (const char *, int); +char *(strrchr) (const char *, int); +char *(strpbrk) (const char *, const char *); +char *(strstr) (const char *, const char *); +#if __STDC_VERSION__ > 201112L +# define memchr(S, C, N) \ + _Generic( \ + /* ensure conversion to a void pointer */ \ + 1 ? (S) : (void*)1, \ + void const*: (void const*)memchr((void const*)(S), (C), (N)), \ + /* volatile qualification of *S is an error for this call */ \ + default: memchr((S), (C), (N)) \ +) +# define strchr(S, C) \ + _Generic( \ + (S), \ + void const*: (char const*)strchr((char const*)(S), (C)), \ + char const*: (char const*)strchr((char const*)(S), (C)), \ + /* volatile qualification of *S is an error for this call */ \ + default: strchr((S), (C)) \ +) +# define strrchr(S, C) \ + _Generic( \ + (S), \ + void const*: (char const*)strrchr((char const*)(S), (C)), \ + char const*: (char const*)strrchr((char const*)(S), (C)), \ + /* volatile qualification of *S is an error for this call */ \ + default: strrchr((S), (C)) \ +) +# define strpbrk(S, A) \ + _Generic( \ + (S), \ + void const*: (char const*)strpbrk((char const*)(S), (A)), \ + char const*: (char const*)strpbrk((char const*)(S), (A)), \ + /* volatile qualification of *S is an error for this call */ \ + default: strpbrk((S), (A)) \ +) +# define strstr(H, N) \ + _Generic( \ + (H), \ + void const*: (char const*)strstr((char const*)(H), (N)), \ + char const*: (char const*)strstr((char const*)(H), (N)), \ + /* volatile qualification of *S is an error for this call */ \ + default: strstr((H), (N)) \ +) +#endif char *strcpy (char *__restrict, const char *__restrict); char *strncpy (char *__restrict, const char *__restrict, size_t); @@ -42,13 +89,8 @@ int strncmp (const char *, const char *, size_t); int strcoll (const char *, const char *); size_t strxfrm (char *__restrict, const char *__restrict, size_t); -char *strchr (const char *, int); -char *strrchr (const char *, int); - size_t strcspn (const char *, const char *); size_t strspn (const char *, const char *); -char *strpbrk (const char *, const char *); -char *strstr (const char *, const char *); char *strtok (char *__restrict, const char *__restrict); size_t strlen (const char *); diff --git a/include/wchar.h b/include/wchar.h index ed5d774d..194f7f8f 100644 --- a/include/wchar.h +++ b/include/wchar.h @@ -61,21 +61,64 @@ int wcsncmp (const wchar_t *, const wchar_t *, size_t); int wcscoll(const wchar_t *, const wchar_t *); size_t wcsxfrm (wchar_t *__restrict, const wchar_t *__restrict, size_t); -wchar_t *wcschr (const wchar_t *, wchar_t); -wchar_t *wcsrchr (const wchar_t *, wchar_t); - size_t wcscspn (const wchar_t *, const wchar_t *); size_t wcsspn (const wchar_t *, const wchar_t *); -wchar_t *wcspbrk (const wchar_t *, const wchar_t *); wchar_t *wcstok (wchar_t *__restrict, const wchar_t *__restrict, wchar_t **__restrict); size_t wcslen (const wchar_t *); -wchar_t *wcsstr (const wchar_t *__restrict, const wchar_t *__restrict); wchar_t *wcswcs (const wchar_t *, const wchar_t *); -wchar_t *wmemchr (const wchar_t *, wchar_t, size_t); +wchar_t *(wmemchr) (const wchar_t *, wchar_t, size_t); +wchar_t *(wcschr) (const wchar_t *, wchar_t); +wchar_t *(wcsrchr) (const wchar_t *, wchar_t); +wchar_t *(wcspbrk) (const wchar_t *, const wchar_t *); +wchar_t *(wcsstr) (const wchar_t *__restrict, const wchar_t *__restrict); +#if __STDC_VERSION__ > 201112L +# define wmemchr(S, C, N) \ + _Generic( \ + (S), \ + void const*: (wchar_t const*)wmemchr((wchar_t const*)(S), (C), (N)), \ + wchar_t const*: (wchar_t const*)wmemchr((wchar_t const*)(S), (C), (N)), \ + /* volatile qualification of *S is an error for this call */ \ + default: wmemchr((S), (C), (N)) \ +) +# define wcschr(S, C) \ + _Generic( \ + (S), \ + void const*: (wchar_t const*)wcschr((wchar_t const*)(S), (C)), \ + wchar_t const*: (wchar_t const*)wcschr((wchar_t const*)(S), (C)), \ + /* volatile qualification of *S is an error for this call */ \ + default: wcschr((S), (C)) \ +) +# define wcsrchr(S, C) \ + _Generic( \ + (S), \ + void const*: (wchar_t const*)wcsrchr((wchar_t const*)(S), (C)), \ + wchar_t const*: (wchar_t const*)wcsrchr((wchar_t const*)(S), (C)), \ + /* volatile qualification of *S is an error for this call */ \ + default: wcsrchr((S), (C)) \ +) +# define wcspbrk(S, A) \ + _Generic( \ + (S), \ + void const*: (wchar_t const*)wcspbrk((wchar_t const*)(S), (A)), \ + wchar_t const*: (wchar_t const*)wcspbrk((wchar_t const*)(S), (A)), \ + /* volatile qualification of *S is an error for this call */ \ + default: wcspbrk((S), (A)) \ +) +# define wcsstr(H, N) \ + _Generic( \ + (H), \ + void const*: (wchar_t const*)wcsstr((wchar_t const*)(H), (N)), \ + wchar_t const*: (wchar_t const*)wcsstr((wchar_t const*)(H), (N)), \ + /* volatile qualification of *S is an error for this call */ \ + default: wcsstr((H), (N)) \ +) +#endif + + int wmemcmp (const wchar_t *, const wchar_t *, size_t); wchar_t *wmemcpy (wchar_t *__restrict, const wchar_t *__restrict, size_t); wchar_t *wmemmove (wchar_t *, const wchar_t *, size_t); diff --git a/src/include/string.h b/src/include/string.h index 2133b5c1..f536c26b 100644 --- a/src/include/string.h +++ b/src/include/string.h @@ -8,4 +8,10 @@ hidden char *__stpcpy(char *, const char *); hidden char *__stpncpy(char *, const char *, size_t); hidden char *__strchrnul(const char *, int); +#undef memchr +#undef strchr +#undef strrchr +#undef strpbrk +#undef strstr + #endif diff --git a/src/include/wchar.h b/src/include/wchar.h index 79f5d0e7..dcd1cce1 100644 --- a/src/include/wchar.h +++ b/src/include/wchar.h @@ -5,5 +5,11 @@ #include "../../include/wchar.h" +#undef wmemchr +#undef wcschr +#undef wcsrchr +#undef wcspbrk +#undef wcsstr + #endif diff --git a/src/string/memchr.c b/src/string/memchr.c index 65f0d789..f11c0573 100644 --- a/src/string/memchr.c +++ b/src/string/memchr.c @@ -8,7 +8,7 @@ #define HIGHS (ONES * (UCHAR_MAX/2+1)) #define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) -void *memchr(const void *src, int c, size_t n) +void *(memchr)(const void *src, int c, size_t n) { const unsigned char *s = src; c = (unsigned char)c; diff --git a/src/string/strchr.c b/src/string/strchr.c index 3cbc828b..3a86beeb 100644 --- a/src/string/strchr.c +++ b/src/string/strchr.c @@ -1,6 +1,6 @@ #include -char *strchr(const char *s, int c) +char *(strchr)(const char *s, int c) { char *r = __strchrnul(s, c); return *(unsigned char *)r == (unsigned char)c ? r : 0; diff --git a/src/string/strpbrk.c b/src/string/strpbrk.c index 55947c64..0941fc51 100644 --- a/src/string/strpbrk.c +++ b/src/string/strpbrk.c @@ -1,6 +1,6 @@ #include -char *strpbrk(const char *s, const char *b) +char *(strpbrk)(const char *s, const char *b) { s += strcspn(s, b); return *s ? (char *)s : 0; diff --git a/src/string/strrchr.c b/src/string/strrchr.c index 98ad1b04..908fd8d4 100644 --- a/src/string/strrchr.c +++ b/src/string/strrchr.c @@ -1,6 +1,6 @@ #include -char *strrchr(const char *s, int c) +char *(strrchr)(const char *s, int c) { return __memrchr(s, c, strlen(s) + 1); } diff --git a/src/string/strstr.c b/src/string/strstr.c index 96657bc2..5c622a82 100644 --- a/src/string/strstr.c +++ b/src/string/strstr.c @@ -135,7 +135,7 @@ static char *twoway_strstr(const unsigned char *h, const unsigned char *n) } } -char *strstr(const char *h, const char *n) +char *(strstr)(const char *h, const char *n) { /* Return immediately on empty needle */ if (!n[0]) return (char *)h; diff --git a/src/string/wcschr.c b/src/string/wcschr.c index 8dfc2f31..2bf7a111 100644 --- a/src/string/wcschr.c +++ b/src/string/wcschr.c @@ -1,6 +1,6 @@ #include -wchar_t *wcschr(const wchar_t *s, wchar_t c) +wchar_t *(wcschr)(const wchar_t *s, wchar_t c) { if (!c) return (wchar_t *)s + wcslen(s); for (; *s && *s != c; s++); diff --git a/src/string/wcspbrk.c b/src/string/wcspbrk.c index 0c72c197..eb76b5ff 100644 --- a/src/string/wcspbrk.c +++ b/src/string/wcspbrk.c @@ -1,6 +1,6 @@ #include -wchar_t *wcspbrk(const wchar_t *s, const wchar_t *b) +wchar_t *(wcspbrk)(const wchar_t *s, const wchar_t *b) { s += wcscspn(s, b); return *s ? (wchar_t *)s : NULL; diff --git a/src/string/wcsrchr.c b/src/string/wcsrchr.c index 8961b9e2..889303f3 100644 --- a/src/string/wcsrchr.c +++ b/src/string/wcsrchr.c @@ -1,6 +1,6 @@ #include -wchar_t *wcsrchr(const wchar_t *s, wchar_t c) +wchar_t *(wcsrchr)(const wchar_t *s, wchar_t c) { const wchar_t *p; for (p=s+wcslen(s); p>=s && *p!=c; p--); diff --git a/src/string/wcsstr.c b/src/string/wcsstr.c index 4caaef3c..8f27dbea 100644 --- a/src/string/wcsstr.c +++ b/src/string/wcsstr.c @@ -90,7 +90,7 @@ static wchar_t *twoway_wcsstr(const wchar_t *h, const wchar_t *n) } } -wchar_t *wcsstr(const wchar_t *restrict h, const wchar_t *restrict n) +wchar_t *(wcsstr)(const wchar_t *restrict h, const wchar_t *restrict n) { /* Return immediately on empty needle or haystack */ if (!n[0]) return (wchar_t *)h; diff --git a/src/string/wmemchr.c b/src/string/wmemchr.c index 2bc2c270..3d761488 100644 --- a/src/string/wmemchr.c +++ b/src/string/wmemchr.c @@ -1,6 +1,6 @@ #include -wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n) +wchar_t *(wmemchr)(const wchar_t *s, wchar_t c, size_t n) { for (; n && *s != c; n--, s++); return n ? (wchar_t *)s : 0; -- 2.34.1