Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Date: Wed, 31 May 2023 16:00:25 +0200
From: Jens Gustedt <Jens.Gustedt@...ia.fr>
To: musl@...ts.openwall.com
Subject: [C23 const 1/2] C23: change bsearch to a macro that respects the const contract

This adds a macro interface to stdlib that 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 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. Therefore we use a trick that maps all
const-qualified targets to void const*.

(3) The case of a wrongly qualified pointer argument would lead to a
misleading diagnostic without the cast.
---
 include/stdlib.h     | 12 +++++++++++-
 src/include/stdlib.h |  2 ++
 src/stdlib/bsearch.c |  2 +-
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/include/stdlib.h b/include/stdlib.h
index 72522cd6..b7abf8c4 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -60,7 +60,17 @@ char *getenv (const char *);
 
 int system (const char *);
 
-void *bsearch (const void *, const void *, size_t, size_t, int (*)(const void *, const void *));
+void * (bsearch) (const void *, const void *, size_t, size_t, int (*)(const void *, const void *));
+#if __STDC_VERSION__ > 201112L
+# define bsearch(K, B, N, S, C)                                         \
+	_Generic(                                                       \
+		/* ensure conversion to a void pointer */               \
+		1 ? (B) : (void*)1,                                     \
+		void const*: (void const*)bsearch((K), (void const*)(B), (N), (S), (C)), \
+		/* volatile qualification of *B is an error for this call */ \
+		default:     bsearch((K), (B), (N), (S), (C))           \
+)
+#endif
 void qsort (void *, size_t, size_t, int (*)(const void *, const void *));
 
 int abs (int);
diff --git a/src/include/stdlib.h b/src/include/stdlib.h
index 812b04de..f0b03df9 100644
--- a/src/include/stdlib.h
+++ b/src/include/stdlib.h
@@ -16,4 +16,6 @@ hidden void *__libc_calloc(size_t, size_t);
 hidden void *__libc_realloc(void *, size_t);
 hidden void __libc_free(void *);
 
+#undef bsearch
+
 #endif
diff --git a/src/stdlib/bsearch.c b/src/stdlib/bsearch.c
index fe050ea3..4f62ea37 100644
--- a/src/stdlib/bsearch.c
+++ b/src/stdlib/bsearch.c
@@ -1,6 +1,6 @@
 #include <stdlib.h>
 
-void *bsearch(const void *key, const void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *))
+void *(bsearch)(const void *key, const void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *))
 {
 	void *try;
 	int sign;
-- 
2.34.1

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.