diff options
author | Alejandro Colomar <alx@kernel.org> | 2022-11-12 00:48:10 +0100 |
---|---|---|
committer | Alejandro Colomar <alx@nginx.com> | 2022-11-15 15:50:38 +0100 |
commit | be3ce4f42507c07e55e7ae6389f3ebd544755bb3 (patch) | |
tree | 8f3b5ced47d2e0118a4369a47076fbb0fc416f74 | |
parent | 947f7c6896c950ca575446e2676424a402efd081 (diff) | |
download | unit-be3ce4f42507c07e55e7ae6389f3ebd544755bb3.tar.gz unit-be3ce4f42507c07e55e7ae6389f3ebd544755bb3.tar.bz2 |
Added nxt_char_cast() macro for casting safely.
This macro is similar to C++'s static_cast(). It allows a very-limited
set of casts to be performed, but rejects most casts. Basically, it
only allows converting from char to u_char and vice-versa, while
respecting the const qualifier.
/*
* SYNOPSIS
* type char_cast(type, string);
*
* ARGUMENTS
* type Type to which 'string' should be cast.
* string String that should be cast to 'type'. It should be a
* pointer, or a pointer to a pointer, to a character type,
* possibly const-qualified.
*
* DESCRIPTION
* This macro resembles C++'s static_cast(). It performs a cast,
* as if '(type) string' was written, but it performs additional
* checks that make sure the cast is limited to character types,
* that the input expression is also of a character type, and that
* it doesn't remove a const qualifier.
*
* It also makes it easier to find all casts easily with grep(1).
*
* CAVEATS
* It doesn't allow using 'volatile'. However, this isn't a big
* issue, since we don't use it with strings. If necessary, the
* macro can be improved to support volatile.
*
* EXAMPLES
* int *ip = &i;
* char *s = "foo";
* const char *cs = "bar";
*
* p = (char *) s; /* OK. Although unsafe, because it
* can be confused with the case in
* the next line. */
* p = (char *) cs; /* Very unsafe; it will probably
* result in Undefined Behaviour. */
*
* p = char_cast(char *, s); // OK.
* p = char_cast(char *, cs); // Compiler error. Cast not allowed.
*
* p = (const char *) s; // OK.
* p = (const char *) cs; // OK.
*
* p = char_cast(const char *, s); // OK.
* p = char_cast(const char *, cs); // OK.
*
* p = (int *) cs; /* Extremely unsafe; it will almost
* certainly result in Undefined
* Behaviour. */
* p = char_cast(int *, cs); // Compiler error. Cast not allowed.
*
* p = (char *) ip; /* Technically OK, but probably
* not what you want. */
* p = char_cast(char *, ip); // Compiler error. Cast not allowed.
*
* SEE ALSO
* _Generic(3)
*/
Acked-by: Andrew Clayton <a.clayton@nginx.com>
Signed-off-by: Alejandro Colomar <alx@nginx.com>
-rw-r--r-- | src/nxt_clang.h | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/src/nxt_clang.h b/src/nxt_clang.h index f465d562..d89e2d69 100644 --- a/src/nxt_clang.h +++ b/src/nxt_clang.h @@ -13,6 +13,43 @@ #define nxt_cdecl +#if (NXT_HAVE_C11_GENERIC) +#define nxt_char_cast(t, p) \ + _Generic(&*(p), \ + u_char *: \ + _Generic((t) NULL, \ + char *: (t) (p), \ + const char *: (t) (p), \ + default: (p)), \ + u_char **: \ + _Generic((t) NULL, \ + char **: (t) (p), \ + default: (p)), \ + const u_char *: \ + _Generic((t) NULL, \ + const char *: (t) (p), \ + default: (p)), \ + char *: \ + _Generic((t) NULL, \ + u_char *: (t) (p), \ + const u_char *: (t) (p), \ + default: (p)), \ + char **: \ + _Generic((t) NULL, \ + u_char **: (t) (p), \ + default: (p)), \ + const char *: \ + _Generic((t) NULL, \ + const u_char *: (t) (p), \ + default: (p)), \ + default: \ + (p) \ + ) +#else +#define nxt_char_cast(t, p) ((t) (p)) +#endif + + #if (NXT_CLANG) /* Any __asm__ directive disables loop vectorization in GCC and Clang. */ |