зеркало из https://github.com/microsoft/git.git
add helpers for allocating flex-array structs
Allocating a struct with a flex array is pretty simple in practice: you over-allocate the struct, then copy some data into the over-allocation. But it can be a slight pain to make sure you're allocating and copying the right amounts. This patch adds a few helpers to turn simple cases of flex-array struct allocation into a one-liner that properly checks for overflow. See the embedded documentation for details. Ideally we could provide a more flexible version that could handle multiple strings, like: FLEX_ALLOC_FMT(ref, name, "%s%s", prefix, name); But we have to implement this as a macro (because of the offset calculation of the flex member), which means we would need all compilers to support variadic macros. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
e7792a74bc
Коммит
3689539127
|
@ -782,6 +782,68 @@ extern FILE *fopen_for_writing(const char *path);
|
|||
#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)
|
||||
{
|
||||
return str ? xstrdup(str) : NULL;
|
||||
|
|
Загрузка…
Ссылка в новой задаче