]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Add archive_integer.h
authorTobias Stoeckmann <tobias@stoeckmann.org>
Wed, 10 Jun 2026 17:56:40 +0000 (19:56 +0200)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Fri, 12 Jun 2026 21:32:36 +0000 (23:32 +0200)
The archive_integer.h header offers various integer operations to
libarchive, utilizing system functionality where possible.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
CMakeLists.txt
Makefile.am
build/cmake/config.h.in
configure.ac
libarchive/CMakeLists.txt
libarchive/archive_integer.h [new file with mode: 0644]

index 319679f75106979558906878db24e2deeecc9515..37697c25f6201d1b23c374e96c909fa3baca56eb 100644 (file)
@@ -774,6 +774,7 @@ CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
 #include <linux/fs.h>
 int main(void) { return FS_IOC_GETFLAGS; }" HAVE_WORKING_FS_IOC_GETFLAGS)
 
+LA_CHECK_INCLUDE_FILE("intsafe.h" HAVE_INTSAFE_H)
 LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H)
 LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H)
 LA_CHECK_INCLUDE_FILE("membership.h" HAVE_MEMBERSHIP_H)
@@ -788,6 +789,7 @@ LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
 LA_CHECK_INCLUDE_FILE("signal.h" HAVE_SIGNAL_H)
 LA_CHECK_INCLUDE_FILE("spawn.h" HAVE_SPAWN_H)
 LA_CHECK_INCLUDE_FILE("stdarg.h" HAVE_STDARG_H)
+LA_CHECK_INCLUDE_FILE("stdckdint.h" HAVE_STDCKDINT_H)
 LA_CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H)
 LA_CHECK_INCLUDE_FILE("stdio.h" HAVE_STDIO_H)
 LA_CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H)
index fef62d4165be06f9810ce121ca05820ece359a1a..250be40599034e6974d1dd2a34d8131557571d86 100644 (file)
@@ -114,6 +114,7 @@ noinst_HEADERS= \
        libarchive/archive_entry_locale.h \
        libarchive/archive_entry_private.h \
        libarchive/archive_hmac_private.h \
+       libarchive/archive_integer.h \
        libarchive/archive_openssl_evp_private.h \
        libarchive/archive_openssl_hmac_private.h \
        libarchive/archive_options_private.h \
index 97ff594767208bcf795a4cbc569fed0400153d55..a082e629865217ddd92a4508b39e294f30f01827 100644 (file)
@@ -684,6 +684,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <iconv.h> header file. */
 #cmakedefine HAVE_ICONV_H 1
 
+/* Define to 1 if you have the <intsafe.h> header file. */
+#cmakedefine HAVE_INTSAFE_H 1
+
 /* Define to 1 if you have the <inttypes.h> header file. */
 #cmakedefine HAVE_INTTYPES_H 1
 
@@ -1025,6 +1028,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <stdarg.h> header file. */
 #cmakedefine HAVE_STDARG_H 1
 
+/* Define to 1 if you have the <stdckdint.h> header file. */
+#cmakedefine HAVE_STDCKDINT_H 1
+
 /* Define to 1 if you have the <stdint.h> header file. */
 #cmakedefine HAVE_STDINT_H 1
 
index 64683896d6b0ff15d143614f8e5bf094da81fdcd..543db407c5238df3a8e470f70cf9b220551273bb 100644 (file)
@@ -365,9 +365,9 @@ AS_VAR_IF([ac_cv_have_decl_FS_IOC_GETFLAGS], [yes],
     [AC_DEFINE_UNQUOTED([HAVE_WORKING_FS_IOC_GETFLAGS], [1],
                     [Define to 1 if you have a working FS_IOC_GETFLAGS])])
 
-AC_CHECK_HEADERS([locale.h membership.h paths.h poll.h pthread.h pwd.h])
-AC_CHECK_HEADERS([readpassphrase.h signal.h spawn.h])
-AC_CHECK_HEADERS([stdarg.h stdint.h stdlib.h string.h])
+AC_CHECK_HEADERS([intsafe.h locale.h membership.h paths.h poll.h pthread.h])
+AC_CHECK_HEADERS([pwd.h readpassphrase.h signal.h spawn.h])
+AC_CHECK_HEADERS([stdarg.h stdckdint.h stdint.h stdlib.h string.h])
 AC_CHECK_HEADERS([sys/acl.h sys/cdefs.h sys/ea.h sys/extattr.h])
 AC_CHECK_HEADERS([sys/ioctl.h sys/mkdev.h sys/mount.h])
 AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/richacl.h])
index 4fb917132ca0eb45c02dfdeebffe2b34e252b08e..b29663742fd6d85dd550694b38779c559e45a701 100644 (file)
@@ -40,6 +40,7 @@ SET(libarchive_SOURCES
   archive_entry_xattr.c
   archive_hmac.c
   archive_hmac_private.h
+  archive_integer.h
   archive_match.c
   archive_openssl_evp_private.h
   archive_openssl_hmac_private.h
diff --git a/libarchive/archive_integer.h b/libarchive/archive_integer.h
new file mode 100644 (file)
index 0000000..f0358b8
--- /dev/null
@@ -0,0 +1,211 @@
+/*-
+ * Copyright (c) 2026 Tobias Stoeckmann
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ARCHIVE_INTEGER_H_INCLUDED
+#define ARCHIVE_INTEGER_H_INCLUDED
+
+#include "archive_platform.h"
+
+/* Note:  This is a purely internal header! */
+/* Do not use this outside of libarchive internal code! */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifdef HAVE_INTSAFE_H
+#define ENABLE_INTSAFE_SIGNED_FUNCTIONS
+#include <intsafe.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_STDCKDINT_H
+#include <stdckdint.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#ifdef HAVE_STDCKDINT_H
+#define USE_STDCKDINT 1
+#elif (__GNUC__ >= 5 && !defined(__INTEL_COMPILER))
+#define USE_BUILTIN 1
+#elif __has_builtin(__builtin_add_overflow)
+#define USE_BUILTIN 1
+#elif defined HAVE_INTSAFE_H
+#define USE_INTSAFE 1
+#endif
+
+/*
+ * Disabling inline keyword for compilers known to choke on it:
+ * - Watcom C++ in C code.  (For any version?)
+ * - SGI MIPSpro
+ * - Microsoft Visual C++ 6.0 (supposedly newer versions too)
+ * - IBM VisualAge 6 (XL v6)
+ * - Sun WorkShop C (SunPro) before 5.9
+ */
+#if defined(__WATCOMC__) || defined(__sgi) || defined(__hpux) || defined(__BORLANDC__)
+#define        inline
+#elif defined(__IBMC__) && __IBMC__ < 700
+#define        inline
+#elif defined(__SUNPRO_C) && __SUNPRO_C < 0x590
+#define inline
+#elif defined(_MSC_VER) || defined(__osf__)
+#define inline __inline
+#endif
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_add_i64(int64_t *result, int64_t a, int64_t b)
+{
+#if USE_STDCKDINT
+       return ckd_add(result, a, b);
+#elif USE_BUILTIN
+       return __builtin_add_overflow(a, b, result);
+#elif USE_INTSAFE
+       LONGLONG res;
+       int ret;
+
+       ret = LongLongAdd(a, b, &res);
+       *result = (int64_t)res;
+       return ret;
+#else
+       if ((b > 0 && a > INT64_MAX - b) ||
+           (b < 0 && a < INT64_MIN - b))
+               return 1;
+
+       *result = a + b;
+       return 0;
+#endif
+}
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_add_u64(uint64_t *result, uint64_t a, uint64_t b)
+{
+#if USE_STDCKDINT
+       return ckd_add(result, a, b);
+#elif USE_BUILTIN
+       return __builtin_add_overflow(a, b, result);
+#elif USE_INTSAFE
+       ULONGLONG res;
+       int ret;
+
+       ret = ULongLongAdd(a, b, &res);
+       *result = (uint64_t)res;
+       return ret;
+#else
+       if (a > UINT64_MAX - b)
+               return 1;
+       *result = a + b;
+       return 0;
+#endif
+}
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_mul_i64(int64_t *result, int64_t a, int64_t b)
+{
+#if USE_STDCKDINT
+       return ckd_mul(result, a, b);
+#elif USE_BUILTIN
+       return __builtin_mul_overflow(a, b, result);
+#elif USE_INTSAFE
+       LONGLONG res;
+       int ret;
+
+       ret = LongLongMult(a, b, &res);
+       *result = (int64_t)res;
+       return ret;
+#else
+       if ((a > 0 && b > 0 && a > INT64_MAX / b) ||
+           (a < 0 && b > 0 && a < INT64_MIN / b) ||
+           (a > 0 && b < 0 && b < INT64_MIN / a) ||
+           (a < 0 && b < 0 && a < INT64_MAX / b))
+               return 1;
+
+       *result = a * b;
+       return 0;
+#endif
+}
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_mul_u64(uint64_t *result, uint64_t a, uint64_t b)
+{
+#if USE_STDCKDINT
+       return ckd_mul(result, a, b);
+#elif USE_BUILTIN
+       return __builtin_mul_overflow(a, b, result);
+#elif USE_INTSAFE
+       ULONGLONG res;
+       int ret;
+
+       ret = ULongLongMult(a, b, &res);
+       *result = (uint64_t)res;
+       return ret;
+#else
+       if (b != 0 && a > UINT64_MAX / b)
+               return 1;
+       *result = a * b;
+       return 0;
+#endif
+}
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_sub_i64(int64_t *result, int64_t a, int64_t b)
+{
+#if USE_STDCKDINT
+       return ckd_sub(result, a, b);
+#elif USE_BUILTIN
+       return __builtin_sub_overflow(a, b, result);
+#elif USE_INTSAFE
+       LONGLONG res;
+       int ret;
+
+       ret = LongLongSub(a, b, &res);
+       *result = (int64_t)res;
+       return ret;
+#else
+       if ((b > 0 && a < INT64_MIN + b) ||
+           (b < 0 && a > INT64_MAX + b))
+               return 1;
+
+       *result = a - b;
+       return 0;
+#endif
+}
+
+#endif