From 62170b995286a6a9ee14784d1b7256322ed02fbb Mon Sep 17 00:00:00 2001 From: David Allan Date: Mon, 5 Apr 2010 13:11:34 -0400 Subject: [PATCH] Implement variable length structure allocator * This patch implements a memory allocator to obtain memory for structures whose last member is a variable length array. C99 refers to these variable length objects as structs containing flexible array members. * Fixed macro parentheses per Eric Blake --- src/util/memory.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/util/memory.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/util/memory.c b/src/util/memory.c index b2ee376187..dd1216b7d4 100644 --- a/src/util/memory.c +++ b/src/util/memory.c @@ -164,6 +164,46 @@ int virReallocN(void *ptrptr, size_t size, size_t count) return 0; } +/** + * Vir_Alloc_Var: + * @ptrptr: pointer to hold address of allocated memory + * @struct_size: size of initial struct + * @element_size: size of array elements + * @count: number of array elements to allocate + * + * Allocate struct_size bytes plus an array of 'count' elements, each + * of size element_size. This sort of allocation is useful for + * receiving the data of certain ioctls and other APIs which return a + * struct in which the last element is an array of undefined length. + * The caller of this type of API is expected to know the length of + * the array that will be returned and allocate a suitable buffer to + * contain the returned data. C99 refers to these variable length + * objects as structs containing flexible array members. + * + * Returns -1 on failure, 0 on success + */ +int virAllocVar(void *ptrptr, size_t struct_size, size_t element_size, size_t count) +{ + size_t alloc_size = 0; + +#if TEST_OOM + if (virAllocTestFail()) + return -1; +#endif + + if (VIR_ALLOC_VAR_OVERSIZED(struct_size, count, element_size)) { + errno = ENOMEM; + return -1; + } + + alloc_size = struct_size + (element_size * count); + *(void **)ptrptr = calloc(1, alloc_size); + if (*(void **)ptrptr == NULL) + return -1; + return 0; +} + + /** * virFree: * @ptrptr: pointer to pointer for address of memory to be freed diff --git a/src/util/memory.h b/src/util/memory.h index 02281735f7..ad458a6bd8 100644 --- a/src/util/memory.h +++ b/src/util/memory.h @@ -48,6 +48,10 @@ int virAlloc(void *ptrptr, size_t size) ATTRIBUTE_RETURN_CHECK; int virAllocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK; int virReallocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK; +int virAllocVar(void *ptrptr, + size_t struct_size, + size_t element_size, + size_t count) ATTRIBUTE_RETURN_CHECK; void virFree(void *ptrptr); /** @@ -88,6 +92,37 @@ void virFree(void *ptrptr); */ # define VIR_REALLOC_N(ptr, count) virReallocN(&(ptr), sizeof(*(ptr)), (count)) +/* + * VIR_ALLOC_VAR_OVERSIZED: + * @M: size of base structure + * @N: number of array elements in trailing array + * @S: size of trailing array elements + * + * Check to make sure that the requested allocation will not cause + * arithmetic overflow in the allocation size. The check is + * essentially the same as that in gnulib's xalloc_oversized. + */ +#define VIR_ALLOC_VAR_OVERSIZED(M, N, S) ((((size_t)-1) - (M)) / (S) < (N)) + +/** + * VIR_ALLOC_VAR: + * @ptr: pointer to hold address of allocated memory + * @type: element type of trailing array + * @count: number of array elements to allocate + * + * Allocate sizeof(*ptr) bytes plus an array of 'count' elements, each + * sizeof('type'). This sort of allocation is useful for receiving + * the data of certain ioctls and other APIs which return a struct in + * which the last element is an array of undefined length. The caller + * of this type of API is expected to know the length of the array + * that will be returned and allocate a suitable buffer to contain the + * returned data. C99 refers to these variable length objects as + * structs containing flexible array members. + + * Returns -1 on failure, 0 on success + */ +#define VIR_ALLOC_VAR(ptr, type, count) virAllocVar(&(ptr), sizeof(*(ptr)), sizeof(type), (count)) + /** * VIR_FREE: * @ptr: pointer holding address to be freed