From ce2379cc29a1923a53fb588e60494dbbc07cb47c Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Wed, 29 Jul 2026 12:57:43 +0200 Subject: [PATCH 1/3] lib/cast.h: rvalue(): Add macro for performing lvalue conversion This macro takes an lvalue, and performs lvalue conversion, resulting in an rvalue. Signed-off-by: Alejandro Colomar --- lib/cast.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cast.h b/lib/cast.h index e8e42e1a0b..d87f8bf36d 100644 --- a/lib/cast.h +++ b/lib/cast.h @@ -11,5 +11,7 @@ #define const_cast(T, p) _Generic(p, const T: (T) (p)) +#define rvalue(lv) ({(lv);}) + #endif // include guard From 711e15b8c147566b5f3904d0f1c9786a54117f27 Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Sun, 11 Jan 2026 00:15:25 +0100 Subject: [PATCH 2/3] lib/: Use rvalue() instead of its pattern This helps document that we're forcing lvalue conversion on purpose, for safety reasons. Signed-off-by: Alejandro Colomar --- lib/alloc/calloc.h | 6 ++---- lib/alloc/malloc.h | 6 ++---- lib/alloc/realloc.h | 9 +++++---- lib/alloc/reallocf.h | 9 +++++---- lib/search/l/lfind.h | 11 ++++++----- lib/sizeof.h | 4 +++- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/alloc/calloc.h b/lib/alloc/calloc.h index db10a685bb..9b32c5ef61 100644 --- a/lib/alloc/calloc.h +++ b/lib/alloc/calloc.h @@ -10,16 +10,14 @@ #include +#include "cast.h" #include "exit_if_null.h" #include "sizeof.h" // calloc_T - calloc type-safe #define calloc_T(n, T) calloc_T_(n, typeas(T)) -#define calloc_T_(n, T) \ -({ \ - (T *){calloc(n, sizeof(T))}; \ -}) +#define calloc_T_(n, T) rvalue((T *){calloc(n, sizeof(T))}) // xcalloc_T - exit-on-error calloc type-safe diff --git a/lib/alloc/malloc.h b/lib/alloc/malloc.h index 1e3a69291a..53602ea732 100644 --- a/lib/alloc/malloc.h +++ b/lib/alloc/malloc.h @@ -11,16 +11,14 @@ #include #include "attr.h" +#include "cast.h" #include "exit_if_null.h" #include "sizeof.h" // malloc_T - malloc type-safe #define malloc_T(n, T) malloc_T_(n, typeas(T)) -#define malloc_T_(n, T) \ -({ \ - (T *){mallocarray(n, sizeof(T))}; \ -}) +#define malloc_T_(n, T) rvalue((T *){mallocarray(n, sizeof(T))}) // xmalloc_T - exit-on-error malloc type-safe diff --git a/lib/alloc/realloc.h b/lib/alloc/realloc.h index ac9f046ec6..448729b382 100644 --- a/lib/alloc/realloc.h +++ b/lib/alloc/realloc.h @@ -10,6 +10,7 @@ #include +#include "cast.h" #include "exit_if_null.h" #include "sizeof.h" @@ -17,10 +18,10 @@ // realloc_T - realloc type-safe #define realloc_T(p, n, T) realloc_T_(p, n, typeas(T)) #define realloc_T_(p, n, T) \ -({ \ - _Generic(p, T *: (void)0); \ - (T *){reallocarray_(p, n, sizeof(T))}; \ -}) +( \ + _Generic(p, T *: (void)0), \ + rvalue((T *){reallocarray_(p, n, sizeof(T))}) \ +) #define reallocarray_(p, n, size) reallocarray(p, (n) ?: 1, (size) ?: 1) diff --git a/lib/alloc/reallocf.h b/lib/alloc/reallocf.h index c3522829d6..0d9a484f26 100644 --- a/lib/alloc/reallocf.h +++ b/lib/alloc/reallocf.h @@ -12,16 +12,17 @@ #include #include "attr.h" +#include "cast.h" #include "sizeof.h" // reallocf_T - realloc free-on-error type-safe #define reallocf_T(p, n, T) reallocf_T_(p, n, typeas(T)) #define reallocf_T_(p, n, T) \ -({ \ - _Generic(p, T *: (void)0); \ - (T *){reallocarrayf_(p, n, sizeof(T))}; \ -}) +( \ + _Generic(p, T *: (void)0), \ + rvalue((T *){reallocarrayf_(p, n, sizeof(T))}) \ +) #define reallocarrayf_(p, n, size) reallocarrayf(p, (n) ?: 1, (size) ?: 1) diff --git a/lib/search/l/lfind.h b/lib/search/l/lfind.h index 7bbd16e0e3..73b53ec4aa 100644 --- a/lib/search/l/lfind.h +++ b/lib/search/l/lfind.h @@ -11,6 +11,7 @@ #include #include +#include "cast.h" #include "search/cmp/cmp.h" #include "sizeof.h" @@ -18,11 +19,11 @@ // lfind_T - linear find type-safe #define lfind_T(T, ...) lfind_T_(typeas(T), __VA_ARGS__) #define lfind_T_(T, k, a, n, cmp) \ -({ \ - _Generic(k, T *: (void)0, const T *: (void)0); \ - _Generic(a, T *: (void)0, const T *: (void)0); \ - (T *){lfind_(k, a, n, sizeof(T), cmp)}; \ -}) +( \ + _Generic(k, T *: (void)0, const T *: (void)0), \ + _Generic(a, T *: (void)0, const T *: (void)0), \ + rvalue((T *){lfind_(k, a, n, sizeof(T), cmp)}) \ +) #define LFIND(T, ...) lfind_T(T, __VA_ARGS__, CMP(T)) diff --git a/lib/sizeof.h b/lib/sizeof.h index 1fc38873dd..e9aa343a0b 100644 --- a/lib/sizeof.h +++ b/lib/sizeof.h @@ -14,10 +14,12 @@ #endif #include +#include "cast.h" + #define typeas(T) typeof((T){0}) -#define ssizeof(x) ({(ssize_t){sizeof(x)};}) +#define ssizeof(x) rvalue((ssize_t){sizeof(x)}) #define memberof(T, member) ((T){}.member) #define WIDTHOF(x) (sizeof(x) * CHAR_BIT) From 86b395f375f13b4fee080d8c4825b55125e11fb1 Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Sun, 11 Jan 2026 00:15:25 +0100 Subject: [PATCH 3/3] lib/cast.h: rvalue(): Use the comma operator to perform lvalue conversion Statement expressions are non-standard, and quite complex within the compiler, so it would be interesting to use simpler compiler features to achieve the same. The comma operator also performs lvalue conversion, and we can use a dummy (void)0 expression to introduce it. This is significantly simpler, and is more portable than the statement expression: it is valid all the way back to C99 (the comma operator and the (void)0 expression are portable to C89, but the compound literal is from C99). By using a simpler feature, we have a smaller risk of running into a compiler bug. Suggested-by: Martin Uecker Cc: Christopher Bazley Cc: Kees Cook Cc: Richard Russon Signed-off-by: Alejandro Colomar --- lib/cast.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cast.h b/lib/cast.h index d87f8bf36d..e96c4a4159 100644 --- a/lib/cast.h +++ b/lib/cast.h @@ -11,7 +11,7 @@ #define const_cast(T, p) _Generic(p, const T: (T) (p)) -#define rvalue(lv) ({(lv);}) +#define rvalue(lv) ((void)0, (lv)) #endif // include guard