[vlc-commits] [Git][videolan/vlc][master] 2 commits: compat: stdckdint: handle signed cases
Thomas Guillem (@tguillem)
gitlab at videolan.org
Wed Feb 19 14:14:03 UTC 2025
Thomas Guillem pushed to branch master at VideoLAN / VLC
Commits:
9cab61e7 by Thomas Guillem at 2025-02-19T14:00:26+00:00
compat: stdckdint: handle signed cases
- - - - -
a7ff7c3c by Thomas Guillem at 2025-02-19T14:00:26+00:00
compat: test stdckdint
Test C23 header, clang/gcc builtins and compat versions.
- - - - -
4 changed files:
- compat/Makefile.am
- compat/stdckdint/stdckdint.h
- + compat/test/ckd.c
- configure.ac
Changes:
=====================================
compat/Makefile.am
=====================================
@@ -13,7 +13,11 @@ dummy.c:
check_PROGRAMS = \
test_heap \
- test_strnstr
+ test_strnstr \
+ test_ckd_ckd \
+ test_ckd_builtin \
+ test_ckd_compat \
+ $(NULL)
AM_TESTS_ENVIRONMENT = ASAN_OPTIONS="allocator_may_return_null=1"
@@ -22,6 +26,16 @@ test_heap_LDADD = libcompat.la
test_strnstr_SOURCES = test/strnstr.c
test_strnstr_LDADD = libcompat.la
+test_ckd_ckd_SOURCES = test/ckd.c
+test_ckd_ckd_CFLAGS = -DTEST_CKD
+if HAVE_STDCKDINT
+test_ckd_ckd_CFLAGS += -DHAVE_CKD
+endif
+test_ckd_builtin_SOURCES = $(test_ckd_ckd_SOURCES)
+test_ckd_builtin_CFLAGS = -DTEST_BUILTIN
+test_ckd_compat_SOURCES = $(test_ckd_ckd_SOURCES)
+test_ckd_compat_CFLAGS = -DTEST_COMPAT
+
if HAVE_DARWIN
check_PROGRAMS += test_clock_nanosleep
=====================================
compat/stdckdint/stdckdint.h
=====================================
@@ -45,8 +45,72 @@ static inline _Bool __ckd_mul_##suffix(type *r, type a, type b) \
return b > 0 && a > (MAX / b); \
}
+# define __ckd_signed_common(suffix, type, MIN, MAX) \
+static inline _Bool __ckd_add_##suffix(type *r, type a, type b) \
+{ \
+ union suffix ua = { .v = a }; \
+ union suffix ub = { .v = b }; \
+ union suffix ur = { .uv = ua.uv + ub.uv }; \
+ *r = ur.v; \
+ if ((b > 0 && a > (MAX - b)) || (b < 0 && a < (MIN - b))) \
+ return 1; \
+ return 0; \
+} \
+\
+static inline _Bool __ckd_sub_##suffix(type *r, type a, type b) \
+{ \
+ union suffix ua = { .v = a }; \
+ union suffix ub = { .v = b }; \
+ union suffix ur = { .uv = ua.uv - ub.uv }; \
+ *r = ur.v; \
+ if ((b < 0 && a > (MAX + b)) || (b > 0 && a < (MIN + b))) \
+ return 1; \
+ return 0; \
+} \
+\
+static inline _Bool __ckd_mul_##suffix(type *r, type a, type b) \
+{ \
+ union suffix ua = { .v = a }; \
+ union suffix ub = { .v = b }; \
+ union suffix ur = { .uv = ua.uv * ub.uv }; \
+ *r = ur.v; \
+ if (a > 0) { \
+ if (b > 0) { \
+ if (a > (MAX / b)) return 1; \
+ } else if (b < 0) { \
+ if (b < (MIN / a)) return 1; \
+ } \
+ } else if (a < 0) { \
+ if (b > 0) { \
+ if (a < (MIN / b)) return 1; \
+ } else if (b < 0) { \
+ if (b < (MAX / a)) return 1; \
+ } \
+ } \
+ return 0; \
+}
+
+# define __ckd_signed(suffix, type, MIN, MAX) \
+union suffix { \
+ unsigned type uv; \
+ type v; \
+}; \
+__ckd_signed_common(suffix, type, MIN, MAX)
+
+# define __ckd_signed_forced(suffix, type, MIN, MAX) \
+union suffix { \
+ unsigned type uv; \
+ signed type v; \
+}; \
+__ckd_signed_common(suffix, signed type, MIN, MAX)
+
# define __ckd_func(op, r, a, b) \
_Generic (*(r), \
+ signed char: __ckd_##op##_sc((signed char *)(r), a, b), \
+ short: __ckd_##op##_ss((short *)(r), a, b), \
+ int: __ckd_##op##_si((int *)(r), a, b), \
+ long: __ckd_##op##_sl((long *)(r), a, b), \
+ long long: __ckd_##op##_sll((long long *)(r), a, b), \
unsigned char: __ckd_##op##_uc((unsigned char *)(r), a, b), \
unsigned short: __ckd_##op##_us((unsigned short *)(r), a, b), \
unsigned int: __ckd_##op##_ui((unsigned int *)(r), a, b), \
@@ -59,6 +123,12 @@ __ckd_unsigned(ui, unsigned int, UINT_MAX)
__ckd_unsigned(ul, unsigned long, ULONG_MAX)
__ckd_unsigned(ull, unsigned long long, ULLONG_MAX)
+__ckd_signed_forced(sc, char, SCHAR_MIN, SCHAR_MAX)
+__ckd_signed(ss, short, SHRT_MIN, SHRT_MAX)
+__ckd_signed(si, int, INT_MIN, INT_MAX)
+__ckd_signed(sl, long, LONG_MIN, LONG_MAX)
+__ckd_signed(sll, long long, LLONG_MIN, LLONG_MAX)
+
# define ckd_add(r, a, b) __ckd_func(add, r, a, b)
# define ckd_sub(r, a, b) __ckd_func(sub, r, a, b)
# define ckd_mul(r, a, b) __ckd_func(mul, r, a, b)
=====================================
compat/test/ckd.c
=====================================
@@ -0,0 +1,115 @@
+/*****************************************************************************
+ * stdckdint.h test case
+ *****************************************************************************
+ * Copyright © 2025 VideoLabs, VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <limits.h>
+#undef NDEBUG
+#include <assert.h>
+
+#if defined (TEST_CKD)
+# ifdef HAVE_CKD
+# include "../include/stdckdint.h" /* Force include on the compiler path */
+# else
+# define SKIP /* can't test it */
+# endif
+#elif defined (TEST_BUILTIN)
+# if defined(__GNUC__) || defined(__clang__)
+# undef __STDC_VERSION_STDCKDINT_H__
+# include "../stdckdint/stdckdint.h" /* Force include on the compat path */
+# else
+# define SKIP /* can't test it */
+# endif
+#elif defined (TEST_COMPAT)
+# undef __STDC_VERSION_STDCKDINT_H__
+# undef __GNUC__
+# undef __clang__
+# include "../stdckdint/stdckdint.h"
+#else
+# error TEST_ not defined
+#endif
+
+int main(void)
+{
+#ifdef SKIP
+ return 77;
+#else
+ unsigned long long ures;
+ long long res;
+
+ /* multiplication */
+
+ /* zero */
+ assert(!ckd_mul(&ures, 0, 0) && ures == 0);
+ assert(!ckd_mul(&ures, 0, 1) && ures == 0);
+ assert(!ckd_mul(&ures, 1, 0) && ures == 0);
+
+ /* small cases */
+ assert(!ckd_mul(&ures, 2, 3) && ures == 6);
+ assert(!ckd_mul(&res, -3, 3) && res == -9);
+ assert(!ckd_mul(&res, -3, -3) && res == 9);
+
+ /* near positive overflow */
+ assert(!ckd_mul(&res, LLONG_MAX, 1) && res == LLONG_MAX);
+ assert(!ckd_mul(&res, LLONG_MAX / 2, 2) && res == LLONG_MAX / 2 * 2);
+ assert(ckd_mul(&res, LLONG_MAX, 2) && res == -2);
+ assert(!ckd_mul(&res, LLONG_MAX, -1) && res == -LLONG_MAX);
+
+ /* near negative overflow */
+ assert(!ckd_mul(&res, LLONG_MIN, 1) && res == LLONG_MIN);
+ assert(ckd_mul(&res, LLONG_MIN, -1) && res == LLONG_MIN);
+
+ /* additions */
+
+ /* small cases */
+ assert(!ckd_add(&ures, 0, 0) && ures == 0);
+ assert(!ckd_add(&ures, 0, 1) && ures == 1);
+ assert(!ckd_add(&ures, 1, 0) && ures == 1);
+ assert(!ckd_add(&ures, 1, 1) && ures == 2);
+
+ /* big edge cases */
+ assert(!ckd_add(&ures, ULLONG_MAX, 0ULL) && ures == ULLONG_MAX);
+ assert(!ckd_add(&ures, ULLONG_MAX - 1ULL, 1ULL) && ures == ULLONG_MAX);
+ assert(ckd_add(&ures, ULLONG_MAX, 1ULL) && ures == 0);
+ assert(ckd_add(&res, LLONG_MAX, 1ULL) && res == LLONG_MIN);
+
+ /* subtractions */
+
+ /* small cases */
+ assert(!ckd_sub(&ures, 0, 0) && ures == 0);
+ assert(!ckd_sub(&ures, 1, 0) && ures == 1);
+ assert(!ckd_sub(&ures, 1, 1) && ures == 0);
+
+ /* 0 - 1 */
+ assert(ckd_sub(&ures, 0, 1) && ures == ULLONG_MAX);
+ assert(!ckd_sub(&res, 0, 1) && res == -1);
+
+ /* edge cases: */
+ assert(!ckd_sub(&ures, ULLONG_MAX, 0) && ures == ULLONG_MAX);
+ assert(!ckd_sub(&ures, ULLONG_MAX, 1) && ures == ULLONG_MAX - 1ULL);
+ assert(ckd_sub(&ures, 0ULL, ULLONG_MAX) && ures == 1);
+ assert(ckd_sub(&ures, 2, 3) && ures == ULLONG_MAX);
+ assert(ckd_sub(&res, LLONG_MIN, 1) && res == LLONG_MAX);
+
+ return 0;
+#endif
+}
=====================================
configure.ac
=====================================
@@ -1016,9 +1016,13 @@ dnl
AC_CHECK_HEADER([stdbit.h],, [
CPPFLAGS="${CPPFLAGS} -I\$(top_srcdir)/compat/stdbit"
])
-AC_CHECK_HEADER([stdckdint.h],, [
+have_stdckdint="no"
+AC_CHECK_HEADER([stdckdint.h], [
+ have_stdckdint="yes"
+], [
CPPFLAGS="${CPPFLAGS} -I\$(top_srcdir)/compat/stdckdint"
])
+AM_CONDITIONAL([HAVE_STDCKDINT], [test "${have_stdckdint}" = "yes"])
dnl POSIX
AC_CHECK_HEADERS([arpa/inet.h net/if.h poll.h pthread.h search.h sys/shm.h sys/socket.h sys/uio.h wordexp.h])
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/21aaf77b87ccfb2fedbd5199c71b96fed051e910...a7ff7c3c00d4bcd3e1230f46a18485b43af0672b
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/21aaf77b87ccfb2fedbd5199c71b96fed051e910...a7ff7c3c00d4bcd3e1230f46a18485b43af0672b
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list