* 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. --- src/util/memory.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/util/memory.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 0 deletions(-) diff --git a/src/util/memory.c b/src/util/memory.c index b2ee376..dd1216b 100644 --- a/src/util/memory.c +++ b/src/util/memory.c @@ -165,6 +165,46 @@ int virReallocN(void *ptrptr, size_t size, size_t count) } /** + * 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 0228173..c717610 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 -- 1.7.0.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list