[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