diff --git a/compat/Makefile.am b/compat/Makefile.am index 2d19183902..7cbb32bdce 100644 --- a/compat/Makefile.am +++ b/compat/Makefile.am @@ -1,4 +1,4 @@ -noinst_HEADERS = stdbit/stdbit.h +noinst_HEADERS = stdbit/stdbit.h stdckdint/stdckdint.h pkglib_LTLIBRARIES = libcompat.la libcompat_la_SOURCES = dummy.c libcompat_la_LIBADD = $(LTLIBOBJS) $(LIBRT) $(LIBM) diff --git a/compat/stdckdint/stdckdint.h b/compat/stdckdint/stdckdint.h new file mode 100644 index 0000000000..b704829d5f --- /dev/null +++ b/compat/stdckdint/stdckdint.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 Rémi Denis-Courmont + * + * 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. + */ + +#ifndef __STDC_VERSION_STDCKDINT_H__ +# define __STDC_VERSION_STDCKDINT_H__ 202311L + +# if defined(__GNUC__) || defined(__clang__) +# define ckd_add(r, a, b) __builtin_add_overflow(a, b, r) +# define ckd_sub(r, a, b) __builtin_sub_overflow(a, b, r) +# define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r) +# else +# include + +# define __ckd_unsigned(suffix, type, MAX) \ +static inline _Bool __ckd_add_##suffix(type *r, type a, type b) \ +{ \ + *r = a + b; \ + return ((type)(a + b)) < a; \ +} \ +\ +static inline _Bool __ckd_sub_##suffix(type *r, type a, type b) \ +{ \ + *r = a - b; \ + return a < b; \ +} \ +\ +static inline _Bool __ckd_mul_##suffix(type *r, type a, type b) \ +{ \ + *r = a * b; \ + return b > 0 && a > (MAX / b); \ +} + +# define __ckd_func(op, r, a, b) \ + _Generic (*(r), \ + 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), \ + unsigned long: __ckd_##op##_ul((unsigned long *)(r), a, b), \ + unsigned long long: __ckd_##op##_ull((unsigned long long *)(r), a, b)) + +__ckd_unsigned(uc, unsigned char, UCHAR_MAX) +__ckd_unsigned(us, unsigned short, USHRT_MAX) +__ckd_unsigned(ui, unsigned int, UINT_MAX) +__ckd_unsigned(ul, unsigned long, ULONG_MAX) +__ckd_unsigned(ull, unsigned long long, ULLONG_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) +# endif +#endif /* __STDC_VERSION_STDCKDINT_H__ */ diff --git a/configure.ac b/configure.ac index 8ecf126854..00a8d15643 100644 --- a/configure.ac +++ b/configure.ac @@ -983,6 +983,9 @@ dnl AC_CHECK_HEADER([stdbit.h],, [ CPPFLAGS="${CPPFLAGS} -I\$(top_srcdir)/compat/stdbit" ]) +AC_CHECK_HEADER([stdckdint.h],, [ + CPPFLAGS="${CPPFLAGS} -I\$(top_srcdir)/compat/stdckdint" +]) dnl POSIX AC_CHECK_HEADERS([arpa/inet.h poll.h pthread.h search.h sys/shm.h sys/socket.h sys/uio.h wordexp.h]) diff --git a/meson.build b/meson.build index beab52a029..7989434761 100644 --- a/meson.build +++ b/meson.build @@ -208,6 +208,7 @@ endif check_c_headers = [ ['stdbit.h'], + ['stdckdint.h'], ['arpa/inet.h'], ['threads.h'], ['netinet/tcp.h'], @@ -269,6 +270,9 @@ endforeach if not cdata.has('HAVE_STDBIT_H') list_inc_dirs += 'compat/stdbit' endif +if not cdata.has('HAVE_STDCKDINT_H') + list_inc_dirs += 'compat/stdckdint' +endif vlc_include_dirs = include_directories(list_inc_dirs) #