summaryrefslogtreecommitdiff
path: root/git-compat-util.h
diff options
context:
space:
mode:
Diffstat (limited to 'git-compat-util.h')
-rw-r--r--git-compat-util.h108
1 files changed, 98 insertions, 10 deletions
diff --git a/git-compat-util.h b/git-compat-util.h
index 2acef3f113..c07e0c1778 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -96,6 +96,14 @@
#define unsigned_add_overflows(a, b) \
((b) > maximum_unsigned_value_of_type(a) - (a))
+/*
+ * Returns true if the multiplication of "a" and "b" will
+ * overflow. The types of "a" and "b" must match and must be unsigned.
+ * Note that this macro evaluates "a" twice!
+ */
+#define unsigned_mult_overflows(a, b) \
+ ((a) && (b) > maximum_unsigned_value_of_type(a) / (a))
+
#ifdef __GNUC__
#define TYPEOF(x) (__typeof__(x))
#else
@@ -669,7 +677,6 @@ extern int git_vsnprintf(char *str, size_t maxsize,
#ifdef __GLIBC_PREREQ
#if __GLIBC_PREREQ(2, 1)
#define HAVE_STRCHRNUL
-#define HAVE_MEMPCPY
#endif
#endif
@@ -683,14 +690,6 @@ static inline char *gitstrchrnul(const char *s, int c)
}
#endif
-#ifndef HAVE_MEMPCPY
-#define mempcpy gitmempcpy
-static inline void *gitmempcpy(void *dest, const void *src, size_t n)
-{
- return (char *)memcpy(dest, src, n) + n;
-}
-#endif
-
#ifdef NO_INET_PTON
int inet_pton(int af, const char *src, void *dst);
#endif
@@ -709,6 +708,32 @@ extern void release_pack_memory(size_t);
typedef void (*try_to_free_t)(size_t);
extern try_to_free_t set_try_to_free_routine(try_to_free_t);
+static inline size_t st_add(size_t a, size_t b)
+{
+ if (unsigned_add_overflows(a, b))
+ die("size_t overflow: %"PRIuMAX" + %"PRIuMAX,
+ (uintmax_t)a, (uintmax_t)b);
+ return a + b;
+}
+#define st_add3(a,b,c) st_add((a),st_add((b),(c)))
+#define st_add4(a,b,c,d) st_add((a),st_add3((b),(c),(d)))
+
+static inline size_t st_mult(size_t a, size_t b)
+{
+ if (unsigned_mult_overflows(a, b))
+ die("size_t overflow: %"PRIuMAX" * %"PRIuMAX,
+ (uintmax_t)a, (uintmax_t)b);
+ return a * b;
+}
+
+static inline size_t st_sub(size_t a, size_t b)
+{
+ if (a < b)
+ die("size_t underflow: %"PRIuMAX" - %"PRIuMAX,
+ (uintmax_t)a, (uintmax_t)b);
+ return a - b;
+}
+
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
# define xalloca(size) (alloca(size))
@@ -741,7 +766,70 @@ extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1);
extern char *xgetcwd(void);
extern FILE *fopen_for_writing(const char *path);
-#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))
+#define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))
+#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))
+
+/*
+ * These functions help you allocate structs with flex arrays, and copy
+ * the data directly into the array. For example, if you had:
+ *
+ * struct foo {
+ * int bar;
+ * char name[FLEX_ARRAY];
+ * };
+ *
+ * you can do:
+ *
+ * struct foo *f;
+ * FLEX_ALLOC_MEM(f, name, src, len);
+ *
+ * to allocate a "foo" with the contents of "src" in the "name" field.
+ * The resulting struct is automatically zero'd, and the flex-array field
+ * is NUL-terminated (whether the incoming src buffer was or not).
+ *
+ * The FLEXPTR_* variants operate on structs that don't use flex-arrays,
+ * but do want to store a pointer to some extra data in the same allocated
+ * block. For example, if you have:
+ *
+ * struct foo {
+ * char *name;
+ * int bar;
+ * };
+ *
+ * you can do:
+ *
+ * struct foo *f;
+ * FLEX_ALLOC_STR(f, name, src);
+ *
+ * and "name" will point to a block of memory after the struct, which will be
+ * freed along with the struct (but the pointer can be repointed anywhere).
+ *
+ * The *_STR variants accept a string parameter rather than a ptr/len
+ * combination.
+ *
+ * Note that these macros will evaluate the first parameter multiple
+ * times, and it must be assignable as an lvalue.
+ */
+#define FLEX_ALLOC_MEM(x, flexname, buf, len) do { \
+ (x) = NULL; /* silence -Wuninitialized for offset calculation */ \
+ (x) = xalloc_flex(sizeof(*(x)), (char *)(&((x)->flexname)) - (char *)(x), (buf), (len)); \
+} while (0)
+#define FLEXPTR_ALLOC_MEM(x, ptrname, buf, len) do { \
+ (x) = xalloc_flex(sizeof(*(x)), sizeof(*(x)), (buf), (len)); \
+ (x)->ptrname = (void *)((x)+1); \
+} while(0)
+#define FLEX_ALLOC_STR(x, flexname, str) \
+ FLEX_ALLOC_MEM((x), flexname, (str), strlen(str))
+#define FLEXPTR_ALLOC_STR(x, ptrname, str) \
+ FLEXPTR_ALLOC_MEM((x), ptrname, (str), strlen(str))
+
+static inline void *xalloc_flex(size_t base_len, size_t offset,
+ const void *src, size_t src_len)
+{
+ unsigned char *ret = xcalloc(1, st_add3(base_len, src_len, 1));
+ memcpy(ret + offset, src, src_len);
+ return ret;
+}
static inline char *xstrdup_or_null(const char *str)
{