From 964063a3693821c367ad43742c5735c65b68d934 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Wed, 11 Dec 2024 21:01:56 +0100
Subject: [PATCH] [winpr,cast] split cast macros to header

* Simplify winpr/assert.h to have the least possible includes
* Move some definitions to winpr/platform.h
* Split and move cast macros to winpr/cast.h
* Add new cast macro for integer casts
---
 winpr/include/winpr/assert-api.h  |  92 ++++++++++++++++
 winpr/include/winpr/assert.h      |  79 +-------------
 winpr/include/winpr/cast.h        | 122 +++++++++++++++++++++
 winpr/include/winpr/crt.h         |   9 +-
 winpr/include/winpr/endian.h      |   7 +-
 winpr/include/winpr/error.h       |  10 +-
 winpr/include/winpr/nt.h          |   7 +-
 winpr/include/winpr/platform.h    | 111 +++++++++++++++++++
 winpr/include/winpr/stream.h      |  12 +--
 winpr/include/winpr/winpr.h       | 174 ++----------------------------
 winpr/libwinpr/crt/CMakeLists.txt |  10 +-
 winpr/libwinpr/crt/assert.c       |  33 ++++++
 12 files changed, 392 insertions(+), 274 deletions(-)
 create mode 100644 winpr/include/winpr/assert-api.h
 create mode 100644 winpr/include/winpr/cast.h
 create mode 100644 winpr/libwinpr/crt/assert.c

diff --git a/winpr/include/winpr/assert-api.h b/winpr/include/winpr/assert-api.h
new file mode 100644
index 000000000000..b003174d5a39
--- /dev/null
+++ b/winpr/include/winpr/assert-api.h
@@ -0,0 +1,92 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Runtime ASSERT macros
+ *
+ * Copyright 2021 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2021 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include <winpr/config.h>
+#include <winpr/platform.h>
+
+#if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0)
+#define winpr_internal_assert(cond, file, fkt, line)        \
+	do                                                      \
+	{                                                       \
+		if (!(cond))                                        \
+			winpr_int_assert(#cond, (file), (fkt), (line)); \
+	} while (0)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+	extern WINPR_NORETURN(void winpr_int_assert(const char* condstr, const char* file,
+	                                            const char* fkt, size_t line));
+
+#ifdef __cplusplus
+}
+#endif
+
+#else
+#define winpr_internal_assert(cond, file, fkt, line) assert(cond)
+#endif
+
+#define WINPR_ASSERT_AT(cond, file, fkt, line)                                                    \
+	do                                                                                            \
+	{                                                                                             \
+		WINPR_PRAGMA_DIAG_PUSH                                                                    \
+		WINPR_PRAGMA_DIAG_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE                              \
+		WINPR_PRAGMA_DIAG_TAUTOLOGICAL_VALUE_RANGE_COMPARE                                        \
+		WINPR_PRAGMA_DIAG_IGNORED_UNKNOWN_PRAGMAS                                                 \
+		WINPR_DO_COVERITY_PRAGMA(coverity compliance block \(deviate "CONSTANT_EXPRESSION_RESULT" \
+		                                                             "WINPR_ASSERT" \)          \
+	    \(deviate "NO_EFFECT"                                                                       \
+		        "WINPR_ASSERT" \))                                                                \
+                                                                                                  \
+		winpr_internal_assert((cond), (file), (fkt), (line));                                     \
+                                                                                                  \
+		WINPR_DO_COVERITY_PRAGMA(coverity compliance end_block "CONSTANT_EXPRESSION_RESULT"       \
+		                                                       "NO_EFFECT")                       \
+		WINPR_PRAGMA_DIAG_POP                                                                     \
+	} while (0)
+#define WINPR_ASSERT(cond) WINPR_ASSERT_AT((cond), __FILE__, __func__, __LINE__)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#if defined(__cplusplus) && (__cplusplus >= 201703L) // C++ 17
+#define WINPR_STATIC_ASSERT(cond) static_assert(cond)
+#elif defined(__cplusplus) && (__cplusplus >= 201103L) // C++ 11
+#define WINPR_STATIC_ASSERT(cond) static_assert(cond, #cond)
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L) // C23
+#define WINPR_STATIC_ASSERT(cond) static_assert(cond)
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) // C11
+#define WINPR_STATIC_ASSERT(cond) _Static_assert(cond, #cond)
+#else
+WINPR_PRAGMA_WARNING("static-assert macro not supported on this platform")
+#define WINPR_STATIC_ASSERT(cond) assert(cond)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h
index 1fb855469c32..8aaca9276faa 100644
--- a/winpr/include/winpr/assert.h
+++ b/winpr/include/winpr/assert.h
@@ -1,9 +1,9 @@
 /**
  * WinPR: Windows Portable Runtime
- * Runtime ASSERT macros
+ * Compatibility header for runtime ASSERT macros
  *
- * Copyright 2021 Armin Novak <armin.novak@thincast.com>
- * Copyright 2021 Thincast Technologies GmbH
+ * Copyright 2024 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2024 Thincast Technologies GmbH
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,75 +29,6 @@
 #include <winpr/wlog.h>
 #include <winpr/debug.h>
 
-#if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0)
-#define winpr_internal_assert(cond, file, fkt, line)        \
-	do                                                      \
-	{                                                       \
-		if (!(cond))                                        \
-			winpr_int_assert(#cond, (file), (fkt), (line)); \
-	} while (0)
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-	static INLINE WINPR_NORETURN(void winpr_int_assert(const char* condstr, const char* file,
-	                                                   const char* fkt, size_t line))
-	{
-		wLog* _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert");
-		WLog_Print(_log_cached_ptr, WLOG_FATAL, "%s [%s:%s:%" PRIuz "]", condstr, file, fkt, line);
-		winpr_log_backtrace_ex(_log_cached_ptr, WLOG_FATAL, 20);
-		abort();
-	}
-
-#ifdef __cplusplus
-}
+#include <winpr/assert-api.h>
+#include <winpr/cast.h>
 #endif
-
-#else
-#define winpr_internal_assert(cond, file, fkt, line) assert(cond)
-#endif
-
-#define WINPR_ASSERT_AT(cond, file, fkt, line)                                                    \
-	do                                                                                            \
-	{                                                                                             \
-		WINPR_PRAGMA_DIAG_PUSH                                                                    \
-		WINPR_PRAGMA_DIAG_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE                              \
-		WINPR_PRAGMA_DIAG_TAUTOLOGICAL_VALUE_RANGE_COMPARE                                        \
-		WINPR_PRAGMA_DIAG_IGNORED_UNKNOWN_PRAGMAS                                                 \
-		WINPR_DO_COVERITY_PRAGMA(coverity compliance block \(deviate "CONSTANT_EXPRESSION_RESULT" \
-		                                                             "WINPR_ASSERT" \)          \
-	    \(deviate "NO_EFFECT"                                                                       \
-		        "WINPR_ASSERT" \))                                                                \
-                                                                                                  \
-		winpr_internal_assert((cond), (file), (fkt), (line));                                     \
-                                                                                                  \
-		WINPR_DO_COVERITY_PRAGMA(coverity compliance end_block "CONSTANT_EXPRESSION_RESULT"       \
-		                                                       "NO_EFFECT")                       \
-		WINPR_PRAGMA_DIAG_POP                                                                     \
-	} while (0)
-#define WINPR_ASSERT(cond) WINPR_ASSERT_AT((cond), __FILE__, __func__, __LINE__)
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-#if defined(__cplusplus) && (__cplusplus >= 201703L) // C++ 17
-#define WINPR_STATIC_ASSERT(cond) static_assert(cond)
-#elif defined(__cplusplus) && (__cplusplus >= 201103L) // C++ 11
-#define WINPR_STATIC_ASSERT(cond) static_assert(cond, #cond)
-#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L) // C23
-#define WINPR_STATIC_ASSERT(cond) static_assert(cond)
-#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) // C11
-#define WINPR_STATIC_ASSERT(cond) _Static_assert(cond, #cond)
-#else
-WINPR_PRAGMA_WARNING("static-assert macro not supported on this platform")
-#define WINPR_STATIC_ASSERT(cond) assert(cond)
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* WINPR_ERROR_H */
diff --git a/winpr/include/winpr/cast.h b/winpr/include/winpr/cast.h
new file mode 100644
index 000000000000..5d7b2ce41d13
--- /dev/null
+++ b/winpr/include/winpr/cast.h
@@ -0,0 +1,122 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Cast macros
+ *
+ * Copyright 2024 Armin Novak <anovak@thincast.com>
+ * Copyright 2024 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <stdint.h>
+
+#include <winpr/assert-api.h>
+
+/**
+ * @brief C++ safe cast macro
+ * @since version 3.10.1
+ */
+#ifdef __cplusplus
+#define WINPR_CXX_COMPAT_CAST(t, val) static_cast<t>(val)
+#else
+#define WINPR_CXX_COMPAT_CAST(t, val) (t)(val)
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+/**
+ * @brief A macro to do dirty casts. Do not use without a good justification!
+ * @param ptr The pointer to cast
+ * @param dstType The data type to cast to
+ * @return The casted pointer
+ * @since version 3.9.0
+ */
+#define WINPR_REINTERPRET_CAST(ptr, srcType, dstType)            \
+	__extension__({                                              \
+		union                                                    \
+		{                                                        \
+			srcType src;                                         \
+			dstType dst;                                         \
+		} cnv;                                                   \
+		WINPR_STATIC_ASSERT(sizeof(srcType) == sizeof(dstType)); \
+		cnv.src = ptr;                                           \
+		cnv.dst;                                                 \
+	})
+
+/**
+ * @brief A macro to do dirty casts. Do not use without a good justification!
+ * @param ptr The pointer to cast
+ * @param dstType The data type to cast to
+ * @return The casted pointer
+ * @since version 3.9.0
+ */
+#define WINPR_CAST_CONST_PTR_AWAY(ptr, dstType) \
+	__extension__({                             \
+		union                                   \
+		{                                       \
+			__typeof(ptr) src;                  \
+			dstType dst;                        \
+		} cnv;                                  \
+		cnv.src = ptr;                          \
+		cnv.dst;                                \
+	})
+
+/**
+ * @brief A macro to do function pointer casts. Do not use without a good justification!
+ * @param ptr The pointer to cast
+ * @param dstType The data type to cast to
+ * @return The casted pointer
+ * @since version 3.9.0
+ */
+#define WINPR_FUNC_PTR_CAST(ptr, dstType)                              \
+	__extension__({                                                    \
+		union                                                          \
+		{                                                              \
+			__typeof(ptr) src;                                         \
+			dstType dst;                                               \
+		} cnv;                                                         \
+		WINPR_STATIC_ASSERT(sizeof(dstType) == sizeof(__typeof(ptr))); \
+		cnv.src = ptr;                                                 \
+		cnv.dst;                                                       \
+	})
+
+#else
+#define WINPR_REINTERPRET_CAST(ptr, srcType, dstType) (dstType) ptr
+#define WINPR_CAST_CONST_PTR_AWAY(ptr, dstType) (dstType) ptr
+#define WINPR_FUNC_PTR_CAST(ptr, dstType) (dstType)(uintptr_t) ptr
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+
+/**
+ * @brief A macro to do checked integer casts.
+ * will check if the value does change by casting to and from the target type and comparing the
+ * values. will also check if the sign of a value changes during conversion.
+ *
+ * @param type the type to cast to
+ * @param var the integer of unknown type to cast
+ * @return The casted integer
+ * @since version 3.10.1
+ */
+#define WINPR_ASSERTING_INT_CAST(type, var)                                                     \
+	__extension__({                                                                             \
+		WINPR_ASSERT((var) ==                                                                   \
+		             WINPR_CXX_COMPAT_CAST(__typeof(var), WINPR_CXX_COMPAT_CAST(type, (var)))); \
+		WINPR_ASSERT((((var) > 0) && (WINPR_CXX_COMPAT_CAST(type, (var)) > 0)) ||               \
+		             (((var) <= 0) && WINPR_CXX_COMPAT_CAST(type, (var)) <= 0));                \
+		WINPR_CXX_COMPAT_CAST(type, (var));                                                     \
+	})
+
+#else
+#define WINPR_ASSERTING_INT_CAST(type, var) WINPR_CXX_COMPAT_CAST(type, var)
+#endif
diff --git a/winpr/include/winpr/crt.h b/winpr/include/winpr/crt.h
index 8375b6fdf57e..825461580c4e 100644
--- a/winpr/include/winpr/crt.h
+++ b/winpr/include/winpr/crt.h
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <winpr/cast.h>
 #include <winpr/platform.h>
 #include <winpr/winpr.h>
 
@@ -108,13 +109,7 @@ static INLINE UINT64 _byteswap_uint64(UINT64 _val)
 
 static INLINE UINT16 _byteswap_ushort(UINT16 _val)
 {
-#ifdef __cplusplus
-#define winpr_byteswap_cast(t, val) static_cast<t>(val)
-#else
-#define winpr_byteswap_cast(t, val) (t)(val)
-#endif
-	return winpr_byteswap_cast(UINT16, ((_val) >> 8U) | ((_val) << 8U));
-#undef winpr_byteswap_cast
+	return WINPR_CXX_COMPAT_CAST(UINT16, ((_val) >> 8U) | ((_val) << 8U));
 }
 
 #endif /* (__GNUC__ > 4) || ... */
diff --git a/winpr/include/winpr/endian.h b/winpr/include/winpr/endian.h
index b3a5eeedff86..ba0b7651310a 100644
--- a/winpr/include/winpr/endian.h
+++ b/winpr/include/winpr/endian.h
@@ -26,12 +26,9 @@
 #include <winpr/wtypes.h>
 #include <winpr/platform.h>
 #include <winpr/assert.h>
+#include <winpr/cast.h>
 
-#ifdef __cplusplus
-#define WINPR_ENDIAN_CAST(t, val) static_cast<t>(val)
-#else
-#define WINPR_ENDIAN_CAST(t, val) (t)(val)
-#endif
+#define WINPR_ENDIAN_CAST(t, val) WINPR_CXX_COMPAT_CAST(t, val)
 
 #ifdef __cplusplus
 extern "C"
diff --git a/winpr/include/winpr/error.h b/winpr/include/winpr/error.h
index 5d83a251cd1b..b883a6e2d31f 100644
--- a/winpr/include/winpr/error.h
+++ b/winpr/include/winpr/error.h
@@ -20,8 +20,7 @@
 #ifndef WINPR_ERROR_H
 #define WINPR_ERROR_H
 
-#include <winpr/platform.h>
-#include <winpr/winpr.h>
+#include <winpr/cast.h>
 #include <winpr/wtypes.h>
 
 #ifdef _WIN32
@@ -147,11 +146,8 @@
 WINPR_PRAGMA_DIAG_PUSH
 WINPR_PRAGMA_DIAG_IGNORED_RESERVED_ID_MACRO
 
-#ifdef __cplusplus
-#define ERROR_CAST(t, val) static_cast<t>(val)
-#else
-#define ERROR_CAST(t, val) (t)(val)
-#endif
+#define ERROR_CAST(t, val) WINPR_CXX_COMPAT_CAST(t, val)
+
 static INLINE HRESULT HRESULT_FROM_WIN32(unsigned long x)
 {
 	HRESULT hx = ERROR_CAST(HRESULT, x);
diff --git a/winpr/include/winpr/nt.h b/winpr/include/winpr/nt.h
index 2662b48f92bd..e2c10c2ef40f 100644
--- a/winpr/include/winpr/nt.h
+++ b/winpr/include/winpr/nt.h
@@ -23,12 +23,9 @@
 #include <winpr/winpr.h>
 #include <winpr/wtypes.h>
 #include <winpr/windows.h>
+#include <winpr/cast.h>
 
-#ifdef __cplusplus
-#define STATUS_CAST(t, val) static_cast<t>(val)
-#else
-#define STATUS_CAST(t, val) (t)(val)
-#endif
+#define STATUS_CAST(t, val) WINPR_CXX_COMPAT_CAST(t, val)
 
 #ifndef _WIN32
 
diff --git a/winpr/include/winpr/platform.h b/winpr/include/winpr/platform.h
index 41225d47b34e..a88066a17b86 100644
--- a/winpr/include/winpr/platform.h
+++ b/winpr/include/winpr/platform.h
@@ -484,4 +484,115 @@ WINPR_PRAGMA_DIAG_IGNORED_RESERVED_ID_MACRO
 
 WINPR_PRAGMA_DIAG_POP
 
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L)
+#define WINPR_DEPRECATED(obj) [[deprecated]] obj
+#define WINPR_DEPRECATED_VAR(text, obj) [[deprecated(text)]] obj
+#define WINPR_NORETURN(obj) [[noreturn]] obj
+#elif defined(WIN32) && !defined(__CYGWIN__)
+#define WINPR_DEPRECATED(obj) __declspec(deprecated) obj
+#define WINPR_DEPRECATED_VAR(text, obj) __declspec(deprecated(text)) obj
+#define WINPR_NORETURN(obj) __declspec(noreturn) obj
+#elif defined(__GNUC__)
+#define WINPR_DEPRECATED(obj) obj __attribute__((deprecated))
+#define WINPR_DEPRECATED_VAR(text, obj) obj __attribute__((deprecated(text)))
+#define WINPR_NORETURN(obj) __attribute__((__noreturn__)) obj
+#else
+#define WINPR_DEPRECATED(obj) obj
+#define WINPR_DEPRECATED_VAR(text, obj) obj
+#define WINPR_NORETURN(obj) obj
+#endif
+
+#ifdef _WIN32
+#define INLINE __inline
+#else
+#define INLINE inline
+#endif
+
+#ifdef WINPR_DLL
+#if defined _WIN32 || defined __CYGWIN__
+#ifdef WINPR_EXPORTS
+#ifdef __GNUC__
+#define WINPR_API __attribute__((dllexport))
+#else
+#define WINPR_API __declspec(dllexport)
+#endif
+#else
+#ifdef __GNUC__
+#define WINPR_API __attribute__((dllimport))
+#else
+#define WINPR_API __declspec(dllimport)
+#endif
+#endif
+#else
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define WINPR_API __attribute__((visibility("default")))
+#else
+#define WINPR_API
+#endif
+#endif
+#else /* WINPR_DLL */
+#define WINPR_API
+#endif
+
+#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ <= 10)
+#define WINPR_ATTR_MALLOC(deallocator, ptrindex) \
+	__attribute__((malloc, warn_unused_result)) /** @since version 3.3.0 */
+#elif defined(__GNUC__)
+#define WINPR_ATTR_MALLOC(deallocator, ptrindex) \
+	__attribute__((malloc(deallocator, ptrindex), warn_unused_result)) /** @since version 3.3.0 */
+#else
+#define WINPR_ATTR_MALLOC(deallocator, ptrindex) __declspec(restrict) /** @since version 3.3.0 */
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+#define WINPR_ATTR_FORMAT_ARG(pos, args) __attribute__((__format__(__printf__, pos, args)))
+#define WINPR_FORMAT_ARG /**/
+#else
+#define WINPR_ATTR_FORMAT_ARG(pos, args)
+#define WINPR_FORMAT_ARG _Printf_format_string_
+#endif
+
+#if defined(EXPORT_ALL_SYMBOLS)
+#define WINPR_LOCAL WINPR_API
+#else
+#if defined _WIN32 || defined __CYGWIN__
+#define WINPR_LOCAL
+#else
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define WINPR_LOCAL __attribute__((visibility("hidden")))
+#else
+#define WINPR_LOCAL
+#endif
+#endif
+#endif
+
+// WARNING: *do not* use thread-local storage for new code because it is not portable
+// It is only used for VirtualChannelInit, and all FreeRDP channels use VirtualChannelInitEx
+// The old virtual channel API is only realistically used on Windows where TLS is available
+#if defined _WIN32 || defined __CYGWIN__
+#ifdef __GNUC__
+#define WINPR_TLS __thread
+#else
+#define WINPR_TLS __declspec(thread)
+#endif
+#elif !defined(__IOS__)
+#define WINPR_TLS __thread
+#else
+// thread-local storage is not supported on iOS
+// don't warn because it isn't actually used on iOS
+#define WINPR_TLS
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+#define WINPR_ALIGN64 __attribute__((aligned(8))) /** @since version 3.4.0 */
+#else
+#ifdef _WIN32
+#define WINPR_ALIGN64 __declspec(align(8)) /** @since version 3.4.0 */
+#else
+#define WINPR_ALIGN64 /** @since version 3.4.0 */
+#endif
+#endif
+
+#define WINPR_UNUSED(x) (void)(x)
+
 #endif /* WINPR_PLATFORM_H */
diff --git a/winpr/include/winpr/stream.h b/winpr/include/winpr/stream.h
index 4e450224f26b..aaf3a53791f6 100644
--- a/winpr/include/winpr/stream.h
+++ b/winpr/include/winpr/stream.h
@@ -28,6 +28,8 @@
 #include <winpr/endian.h>
 #include <winpr/synch.h>
 #include <winpr/assert.h>
+#include <winpr/cast.h>
+#include <winpr/wlog.h>
 
 #ifdef __cplusplus
 extern "C"
@@ -56,11 +58,7 @@ extern "C"
 	WINPR_API BOOL Stream_EnsureCapacity(wStream* s, size_t size);
 	WINPR_API BOOL Stream_EnsureRemainingCapacity(wStream* s, size_t size);
 
-#ifdef __cplusplus
-#define WINPR_STREAM_CAST(t, val) static_cast<t>(val)
-#else
-#define WINPR_STREAM_CAST(t, val) (t)(val)
-#endif
+#define WINPR_STREAM_CAST(t, val) WINPR_CXX_COMPAT_CAST(t, val)
 
 #define Stream_CheckAndLogRequiredCapacityOfSize(tag, s, nmemb, size)                         \
 	Stream_CheckAndLogRequiredCapacityEx(tag, WLOG_WARN, s, nmemb, size, "%s(%s:%" PRIuz ")", \
@@ -1252,7 +1250,7 @@ extern "C"
  *
  *  @since version 3.9.0
  */
-#define Stream_GetBufferAs(_s, _b) _b = Stream_BufferAs(_s, typeof(_b))
+#define Stream_GetBufferAs(_s, _b) _b = Stream_BufferAs(_s, __typeof(_b))
 
 #define Stream_PointerAs(s, type) WINPR_STREAM_CAST(type*, Stream_Pointer(s))
 
@@ -1274,7 +1272,7 @@ extern "C"
  *
  *  @since version 3.9.0
  */
-#define Stream_GetPointerAs(_s, _p) _p = Stream_PointerAs(_s, typeof(_p))
+#define Stream_GetPointerAs(_s, _p) _p = Stream_PointerAs(_s, __typeof(_p))
 
 #if defined(WITH_WINPR_DEPRECATED)
 	WINPR_API WINPR_DEPRECATED_VAR("Use Stream_SetPosition instead",
diff --git a/winpr/include/winpr/winpr.h b/winpr/include/winpr/winpr.h
index 126f8e1e32e5..f760476ec83e 100644
--- a/winpr/include/winpr/winpr.h
+++ b/winpr/include/winpr/winpr.h
@@ -20,114 +20,11 @@
 #define WINPR_H
 
 #include <winpr/platform.h>
+#include <winpr/cast.h>
 
-#ifdef WINPR_DLL
-#if defined _WIN32 || defined __CYGWIN__
-#ifdef WINPR_EXPORTS
-#ifdef __GNUC__
-#define WINPR_API __attribute__((dllexport))
-#else
-#define WINPR_API __declspec(dllexport)
-#endif
-#else
-#ifdef __GNUC__
-#define WINPR_API __attribute__((dllimport))
-#else
-#define WINPR_API __declspec(dllimport)
-#endif
-#endif
-#else
-#if defined(__GNUC__) && (__GNUC__ >= 4)
-#define WINPR_API __attribute__((visibility("default")))
-#else
-#define WINPR_API
-#endif
-#endif
-#else /* WINPR_DLL */
-#define WINPR_API
-#endif
-
-#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ <= 10)
-#define WINPR_ATTR_MALLOC(deallocator, ptrindex) \
-	__attribute__((malloc, warn_unused_result)) /** @since version 3.3.0 */
-#elif defined(__GNUC__)
-#define WINPR_ATTR_MALLOC(deallocator, ptrindex) \
-	__attribute__((malloc(deallocator, ptrindex), warn_unused_result)) /** @since version 3.3.0 */
-#else
-#define WINPR_ATTR_MALLOC(deallocator, ptrindex) __declspec(restrict) /** @since version 3.3.0 */
-#endif
-
-#if defined(__GNUC__) || defined(__clang__)
-#define WINPR_ATTR_FORMAT_ARG(pos, args) __attribute__((__format__(__printf__, pos, args)))
-#define WINPR_FORMAT_ARG /**/
-#else
-#define WINPR_ATTR_FORMAT_ARG(pos, args)
-#define WINPR_FORMAT_ARG _Printf_format_string_
-#endif
-
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L)
-#define WINPR_DEPRECATED(obj) [[deprecated]] obj
-#define WINPR_DEPRECATED_VAR(text, obj) [[deprecated(text)]] obj
-#define WINPR_NORETURN(obj) [[noreturn]] obj
-#elif defined(WIN32) && !defined(__CYGWIN__)
-#define WINPR_DEPRECATED(obj) __declspec(deprecated) obj
-#define WINPR_DEPRECATED_VAR(text, obj) __declspec(deprecated(text)) obj
-#define WINPR_NORETURN(obj) __declspec(noreturn) obj
-#elif defined(__GNUC__)
-#define WINPR_DEPRECATED(obj) obj __attribute__((deprecated))
-#define WINPR_DEPRECATED_VAR(text, obj) obj __attribute__((deprecated(text)))
-#define WINPR_NORETURN(obj) __attribute__((__noreturn__)) obj
-#else
-#define WINPR_DEPRECATED(obj) obj
-#define WINPR_DEPRECATED_VAR(text, obj) obj
-#define WINPR_NORETURN(obj) obj
-#endif
-
-#if defined(EXPORT_ALL_SYMBOLS)
-#define WINPR_LOCAL WINPR_API
-#else
-#if defined _WIN32 || defined __CYGWIN__
-#define WINPR_LOCAL
-#else
-#if defined(__GNUC__) && (__GNUC__ >= 4)
-#define WINPR_LOCAL __attribute__((visibility("hidden")))
-#else
-#define WINPR_LOCAL
-#endif
-#endif
-#endif
-
-// WARNING: *do not* use thread-local storage for new code because it is not portable
-// It is only used for VirtualChannelInit, and all FreeRDP channels use VirtualChannelInitEx
-// The old virtual channel API is only realistically used on Windows where TLS is available
-#if defined _WIN32 || defined __CYGWIN__
-#ifdef __GNUC__
-#define WINPR_TLS __thread
-#else
-#define WINPR_TLS __declspec(thread)
-#endif
-#elif !defined(__IOS__)
-#define WINPR_TLS __thread
-#else
-// thread-local storage is not supported on iOS
-// don't warn because it isn't actually used on iOS
-#define WINPR_TLS
-#endif
-
-#ifdef _WIN32
-#define INLINE __inline
-#else
-#define INLINE inline
-#endif
-
-#if defined(__GNUC__) || defined(__clang__)
-#define WINPR_ALIGN64 __attribute__((aligned(8))) /** @since version 3.4.0 */
-#else
-#ifdef _WIN32
-#define WINPR_ALIGN64 __declspec(align(8)) /** @since version 3.4.0 */
-#else
-#define WINPR_ALIGN64 /** @since version 3.4.0 */
-#endif
+#ifdef __cplusplus
+extern "C"
+{
 #endif
 
 WINPR_API void winpr_get_version(int* major, int* minor, int* revision);
@@ -135,67 +32,8 @@ WINPR_API const char* winpr_get_version_string(void);
 WINPR_API const char* winpr_get_build_revision(void);
 WINPR_API const char* winpr_get_build_config(void);
 
-#define WINPR_UNUSED(x) (void)(x)
-
-#if defined(__GNUC__) || defined(__clang__)
-/**
- * @brief A macro to do dirty casts. Do not use without a good justification!
- * @param ptr The pointer to cast
- * @param dstType The data type to cast to
- * @return The casted pointer
- * @since version 3.9.0
- */
-#define WINPR_REINTERPRET_CAST(ptr, srcType, dstType)            \
-	__extension__({                                              \
-		union                                                    \
-		{                                                        \
-			srcType src;                                         \
-			dstType dst;                                         \
-		} cnv;                                                   \
-		WINPR_STATIC_ASSERT(sizeof(srcType) == sizeof(dstType)); \
-		cnv.src = ptr;                                           \
-		cnv.dst;                                                 \
-	})
-
-/**
- * @brief A macro to do dirty casts. Do not use without a good justification!
- * @param ptr The pointer to cast
- * @param dstType The data type to cast to
- * @return The casted pointer
- * @since version 3.9.0
- */
-#define WINPR_CAST_CONST_PTR_AWAY(ptr, dstType) \
-	__extension__({                             \
-		union                                   \
-		{                                       \
-			typeof(ptr) src;                    \
-			dstType dst;                        \
-		} cnv;                                  \
-		cnv.src = ptr;                          \
-		cnv.dst;                                \
-	})
-
-/**
- * @brief A macro to do function pointer casts. Do not use without a good justification!
- * @param ptr The pointer to cast
- * @param dstType The data type to cast to
- * @return The casted pointer
- * @since version 3.9.0
- */
-#define WINPR_FUNC_PTR_CAST(ptr, dstType) \
-	__extension__({                       \
-		union                             \
-		{                                 \
-			typeof(ptr) src;              \
-			dstType dst;                  \
-		} cnv;                            \
-		cnv.src = ptr;                    \
-		cnv.dst;                          \
-	})
-#else
-#define WINPR_REINTERPRET_CAST(ptr, srcType, dstType) (dstType) ptr
-#define WINPR_CAST_CONST_PTR_AWAY(ptr, dstType) (dstType) ptr
-#define WINPR_FUNC_PTR_CAST(ptr, dstType) (dstType)(uintptr_t) ptr
+#ifdef __cplusplus
+}
 #endif
 
 #endif /* WINPR_H */
diff --git a/winpr/libwinpr/crt/CMakeLists.txt b/winpr/libwinpr/crt/CMakeLists.txt
index 18f6ad139fea..684ed1a91834 100644
--- a/winpr/libwinpr/crt/CMakeLists.txt
+++ b/winpr/libwinpr/crt/CMakeLists.txt
@@ -15,7 +15,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set(CRT_FILES alignment.c conversion.c buffer.c memory.c unicode.c string.c)
+set(CRT_FILES
+    alignment.c
+    conversion.c
+    buffer.c
+    memory.c
+    unicode.c
+    string.c
+    assert.c
+)
 
 if(WITH_UNICODE_BUILTIN)
   list(APPEND CRT_FILES unicode_builtin.c)
diff --git a/winpr/libwinpr/crt/assert.c b/winpr/libwinpr/crt/assert.c
new file mode 100644
index 000000000000..cd66f531bd41
--- /dev/null
+++ b/winpr/libwinpr/crt/assert.c
@@ -0,0 +1,33 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Runtime ASSERT macros
+ *
+ * Copyright 2021 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2021 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/assert.h>
+#include <winpr/wlog.h>
+#include <winpr/debug.h>
+
+#if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0)
+void winpr_int_assert(const char* condstr, const char* file, const char* fkt, size_t line)
+{
+	wLog* _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert");
+	WLog_Print(_log_cached_ptr, WLOG_FATAL, "%s [%s:%s:%" PRIuz "]", condstr, file, fkt, line);
+	winpr_log_backtrace_ex(_log_cached_ptr, WLOG_FATAL, 20);
+	abort();
+}
+#endif

From 795914e50c96cc1d62cdd8c28562b0e4689a1949 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Thu, 12 Dec 2024 18:31:24 +0100
Subject: [PATCH] [winpr,assert] always compile in assert helper

---
 winpr/include/winpr/assert-api.h | 18 ++++++++++++------
 winpr/libwinpr/crt/assert.c      |  2 --
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/winpr/include/winpr/assert-api.h b/winpr/include/winpr/assert-api.h
index b003174d5a39..b1e32217eb6d 100644
--- a/winpr/include/winpr/assert-api.h
+++ b/winpr/include/winpr/assert-api.h
@@ -34,22 +34,28 @@
 			winpr_int_assert(#cond, (file), (fkt), (line)); \
 	} while (0)
 
+#else
+#define winpr_internal_assert(cond, file, fkt, line) assert(cond)
+#endif
+
 #ifdef __cplusplus
 extern "C"
 {
 #endif
 
-	extern WINPR_NORETURN(void winpr_int_assert(const char* condstr, const char* file,
-	                                            const char* fkt, size_t line));
+	/* this function meant only to be used by WINPR_ASSERT
+	 * it needs to be exported as our assert implementation calls this for debug logging.
+	 *
+	 * also export when WITH_VERBOSE_WINPR_ASSERT is disabled as other software might compile with
+	 * it enabled
+	 */
+	WINPR_API WINPR_NORETURN(void winpr_int_assert(const char* condstr, const char* file,
+	                                               const char* fkt, size_t line));
 
 #ifdef __cplusplus
 }
 #endif
 
-#else
-#define winpr_internal_assert(cond, file, fkt, line) assert(cond)
-#endif
-
 #define WINPR_ASSERT_AT(cond, file, fkt, line)                                                    \
 	do                                                                                            \
 	{                                                                                             \
diff --git a/winpr/libwinpr/crt/assert.c b/winpr/libwinpr/crt/assert.c
index cd66f531bd41..bfc4684320d2 100644
--- a/winpr/libwinpr/crt/assert.c
+++ b/winpr/libwinpr/crt/assert.c
@@ -22,7 +22,6 @@
 #include <winpr/wlog.h>
 #include <winpr/debug.h>
 
-#if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0)
 void winpr_int_assert(const char* condstr, const char* file, const char* fkt, size_t line)
 {
 	wLog* _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert");
@@ -30,4 +29,3 @@ void winpr_int_assert(const char* condstr, const char* file, const char* fkt, si
 	winpr_log_backtrace_ex(_log_cached_ptr, WLOG_FATAL, 20);
 	abort();
 }
-#endif

From 4b277189ee2bfc0d66a843c36dd42150d611c904 Mon Sep 17 00:00:00 2001
From: Armin Novak <armin.novak@thincast.com>
Date: Wed, 7 Jan 2026 11:28:11 +0100
Subject: [PATCH] [winpr,cast] use temporary variable in
 WINPR_ASSERTING_INT_CAST

avoid calling C++ functions twice by storing the input variable
---
 winpr/include/winpr/cast.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/winpr/include/winpr/cast.h b/winpr/include/winpr/cast.h
index 5d7b2ce41d13..804ea0f6688d 100644
--- a/winpr/include/winpr/cast.h
+++ b/winpr/include/winpr/cast.h
@@ -108,8 +108,9 @@
  * @return The casted integer
  * @since version 3.10.1
  */
-#define WINPR_ASSERTING_INT_CAST(type, var)                                                     \
+#define WINPR_ASSERTING_INT_CAST(type, ivar)                                                    \
 	__extension__({                                                                             \
+		__typeof(ivar) var = ivar;                                                              \
 		WINPR_ASSERT((var) ==                                                                   \
 		             WINPR_CXX_COMPAT_CAST(__typeof(var), WINPR_CXX_COMPAT_CAST(type, (var)))); \
 		WINPR_ASSERT((((var) > 0) && (WINPR_CXX_COMPAT_CAST(type, (var)) > 0)) ||               \
