From 4ffb0358dead886322c255db98e196db8728ea6e Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 28 Apr 2008 21:44:54 +0000 Subject: [PATCH] Added safer lowlevel memory allocation APis. Converted hash.c and capabilities.c to use them --- ChangeLog | 10 ++++ proxy/Makefile.am | 1 + src/Makefile.am | 1 + src/capabilities.c | 121 +++++++++++++++++---------------------- src/hash.c | 114 +++++++++++++++++------------------- src/internal.h | 16 +++++- src/memory.c | 140 +++++++++++++++++++++++++++++++++++++++++++++ src/memory.h | 82 ++++++++++++++++++++++++++ 8 files changed, 357 insertions(+), 128 deletions(-) create mode 100644 src/memory.c create mode 100644 src/memory.h diff --git a/ChangeLog b/ChangeLog index 9b1ba0eccb..0f3938f263 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Mon Apr 28 17:24:22 EST 2008 Daniel P. Berrange + + * src/memory.h, src/memory.c: Added safer APIs for dealing + with low level memory allocation. + * src/hash.c, src/capabilities.c: Convert to new memory + allocation APIs + * src/internal.h: Define ATTRIBUTE_RETURN_CHECK and fix + type in virDebug no-op impl + * proxy/Makefile.am: Build and link against memory.c + Mon Apr 28 10:24:22 EST 2008 Daniel P. Berrange * src/buf.c, src/buf.h: Change API to move errors checks to diff --git a/proxy/Makefile.am b/proxy/Makefile.am index 789a6429fa..2fe77c8209 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -14,6 +14,7 @@ libvirt_proxy_SOURCES = libvirt_proxy.c @top_srcdir@/src/xend_internal.c \ @top_srcdir@/src/sexpr.c @top_srcdir@/src/xml.c \ @top_srcdir@/src/xs_internal.c @top_srcdir@/src/buf.c \ @top_srcdir@/src/capabilities.c \ + @top_srcdir@/src/memory.c \ @top_srcdir@/src/util.c \ @top_srcdir@/src/uuid.c libvirt_proxy_LDFLAGS = $(WARN_CFLAGS) diff --git a/src/Makefile.am b/src/Makefile.am index 7110420914..2898a8e198 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,6 +33,7 @@ CLIENT_SOURCES = \ libvirt.c internal.h \ gnutls_1_0_compat.h \ socketcompat.h \ + memory.c memory.h \ hash.c hash.h \ test.c test.h \ buf.c buf.h \ diff --git a/src/capabilities.c b/src/capabilities.c index 8965c11cb5..cf95751ea9 100644 --- a/src/capabilities.c +++ b/src/capabilities.c @@ -25,6 +25,7 @@ #include "capabilities.h" #include "buf.h" +#include "memory.h" /** @@ -42,7 +43,7 @@ virCapabilitiesNew(const char *arch, { virCapsPtr caps; - if ((caps = calloc(1, sizeof(*caps))) == NULL) + if (VIR_ALLOC(caps) < 0) goto no_memory; if ((caps->host.arch = strdup(arch)) == NULL) @@ -60,53 +61,53 @@ virCapabilitiesNew(const char *arch, static void virCapabilitiesFreeHostNUMACell(virCapsHostNUMACellPtr cell) { - free(cell->cpus); - free(cell); + VIR_FREE(cell->cpus); + VIR_FREE(cell); } static void virCapabilitiesFreeGuestDomain(virCapsGuestDomainPtr dom) { int i; - free(dom->info.emulator); - free(dom->info.loader); + VIR_FREE(dom->info.emulator); + VIR_FREE(dom->info.loader); for (i = 0 ; i < dom->info.nmachines ; i++) - free(dom->info.machines[i]); - free(dom->info.machines); - free(dom->type); + VIR_FREE(dom->info.machines[i]); + VIR_FREE(dom->info.machines); + VIR_FREE(dom->type); - free(dom); + VIR_FREE(dom); } static void virCapabilitiesFreeGuestFeature(virCapsGuestFeaturePtr feature) { - free(feature->name); - free(feature); + VIR_FREE(feature->name); + VIR_FREE(feature); } static void virCapabilitiesFreeGuest(virCapsGuestPtr guest) { int i; - free(guest->ostype); + VIR_FREE(guest->ostype); - free(guest->arch.name); - free(guest->arch.defaultInfo.emulator); - free(guest->arch.defaultInfo.loader); + VIR_FREE(guest->arch.name); + VIR_FREE(guest->arch.defaultInfo.emulator); + VIR_FREE(guest->arch.defaultInfo.loader); for (i = 0 ; i < guest->arch.defaultInfo.nmachines ; i++) - free(guest->arch.defaultInfo.machines[i]); - free(guest->arch.defaultInfo.machines); + VIR_FREE(guest->arch.defaultInfo.machines[i]); + VIR_FREE(guest->arch.defaultInfo.machines); for (i = 0 ; i < guest->arch.ndomains ; i++) virCapabilitiesFreeGuestDomain(guest->arch.domains[i]); - free(guest->arch.domains); + VIR_FREE(guest->arch.domains); for (i = 0 ; i < guest->nfeatures ; i++) virCapabilitiesFreeGuestFeature(guest->features[i]); - free(guest->features); + VIR_FREE(guest->features); - free(guest); + VIR_FREE(guest); } @@ -122,21 +123,21 @@ virCapabilitiesFree(virCapsPtr caps) { for (i = 0 ; i < caps->nguests ; i++) virCapabilitiesFreeGuest(caps->guests[i]); - free(caps->guests); + VIR_FREE(caps->guests); for (i = 0 ; i < caps->host.nfeatures ; i++) - free(caps->host.features[i]); - free(caps->host.features); + VIR_FREE(caps->host.features[i]); + VIR_FREE(caps->host.features); for (i = 0 ; i < caps->host.nnumaCell ; i++) virCapabilitiesFreeHostNUMACell(caps->host.numaCell[i]); - free(caps->host.numaCell); + VIR_FREE(caps->host.numaCell); for (i = 0 ; i < caps->host.nmigrateTrans ; i++) - free(caps->host.migrateTrans[i]); - free(caps->host.migrateTrans); + VIR_FREE(caps->host.migrateTrans[i]); + VIR_FREE(caps->host.migrateTrans); - free(caps->host.arch); - free(caps); + VIR_FREE(caps->host.arch); + VIR_FREE(caps); } @@ -151,12 +152,9 @@ int virCapabilitiesAddHostFeature(virCapsPtr caps, const char *name) { - char **features; - - if ((features = realloc(caps->host.features, - sizeof(*features) * (caps->host.nfeatures+1))) == NULL) + if (VIR_REALLOC_N(caps->host.features, + caps->host.nfeatures + 1) < 0) return -1; - caps->host.features = features; if ((caps->host.features[caps->host.nfeatures] = strdup(name)) == NULL) return -1; @@ -177,12 +175,9 @@ int virCapabilitiesAddHostMigrateTransport(virCapsPtr caps, const char *name) { - char **migrateTrans; - - if ((migrateTrans = realloc(caps->host.migrateTrans, - sizeof(*migrateTrans) * (caps->host.nmigrateTrans+1))) == NULL) + if (VIR_REALLOC_N(caps->host.migrateTrans, + caps->host.nmigrateTrans + 1) < 0) return -1; - caps->host.migrateTrans = migrateTrans; if ((caps->host.migrateTrans[caps->host.nmigrateTrans] = strdup(name)) == NULL) return -1; @@ -208,19 +203,18 @@ virCapabilitiesAddHostNUMACell(virCapsPtr caps, int ncpus, const int *cpus) { - virCapsHostNUMACellPtr cell, *cells; + virCapsHostNUMACellPtr cell; - if ((cells = realloc(caps->host.numaCell, - sizeof(*cells) * (caps->host.nnumaCell+1))) == NULL) + if (VIR_REALLOC_N(caps->host.numaCell, + caps->host.nnumaCell + 1) < 0) return -1; - caps->host.numaCell = cells; - if ((cell = calloc(1, sizeof(cell))) == NULL) + if (VIR_ALLOC(cell) < 0) return -1; caps->host.numaCell[caps->host.nnumaCell] = cell; - if ((caps->host.numaCell[caps->host.nnumaCell]->cpus = - malloc(ncpus * sizeof(*cpus))) == NULL) + if (VIR_ALLOC_N(caps->host.numaCell[caps->host.nnumaCell]->cpus, + ncpus) < 0) return -1; memcpy(caps->host.numaCell[caps->host.nnumaCell]->cpus, cpus, @@ -259,10 +253,10 @@ virCapabilitiesAddGuest(virCapsPtr caps, int nmachines, const char *const *machines) { - virCapsGuestPtr guest, *guests; + virCapsGuestPtr guest; int i; - if ((guest = calloc(1, sizeof(*guest))) == NULL) + if (VIR_ALLOC(guest) < 0) goto no_memory; if ((guest->ostype = strdup(ostype)) == NULL) @@ -279,8 +273,8 @@ virCapabilitiesAddGuest(virCapsPtr caps, (guest->arch.defaultInfo.loader = strdup(loader)) == NULL) goto no_memory; if (nmachines) { - if ((guest->arch.defaultInfo.machines = - calloc(nmachines, sizeof(*guest->arch.defaultInfo.machines))) == NULL) + if (VIR_ALLOC_N(guest->arch.defaultInfo.machines, + nmachines) < 0) goto no_memory; for (i = 0 ; i < nmachines ; i++) { if ((guest->arch.defaultInfo.machines[i] = strdup(machines[i])) == NULL) @@ -289,11 +283,9 @@ virCapabilitiesAddGuest(virCapsPtr caps, } } - if ((guests = realloc(caps->guests, - sizeof(*guests) * - (caps->nguests + 1))) == NULL) + if (VIR_REALLOC_N(caps->guests, + caps->nguests + 1) < 0) goto no_memory; - caps->guests = guests; caps->guests[caps->nguests] = guest; caps->nguests++; @@ -325,10 +317,10 @@ virCapabilitiesAddGuestDomain(virCapsGuestPtr guest, int nmachines, const char *const *machines) { - virCapsGuestDomainPtr dom, *doms; + virCapsGuestDomainPtr dom; int i; - if ((dom = calloc(1, sizeof(*dom))) == NULL) + if (VIR_ALLOC(dom) < 0) goto no_memory; if ((dom->type = strdup(hvtype)) == NULL) @@ -341,8 +333,7 @@ virCapabilitiesAddGuestDomain(virCapsGuestPtr guest, (dom->info.loader = strdup(loader)) == NULL) goto no_memory; if (nmachines) { - if ((dom->info.machines = - calloc(nmachines, sizeof(*dom->info.machines))) == NULL) + if (VIR_ALLOC_N(dom->info.machines, nmachines) < 0) goto no_memory; for (i = 0 ; i < nmachines ; i++) { if ((dom->info.machines[i] = strdup(machines[i])) == NULL) @@ -351,11 +342,9 @@ virCapabilitiesAddGuestDomain(virCapsGuestPtr guest, } } - if ((doms = realloc(guest->arch.domains, - sizeof(*doms) * - (guest->arch.ndomains + 1))) == NULL) + if (VIR_REALLOC_N(guest->arch.domains, + guest->arch.ndomains + 1) < 0) goto no_memory; - guest->arch.domains = doms; guest->arch.domains[guest->arch.ndomains] = dom; guest->arch.ndomains++; @@ -383,9 +372,9 @@ virCapabilitiesAddGuestFeature(virCapsGuestPtr guest, int defaultOn, int toggle) { - virCapsGuestFeaturePtr feature, *features; + virCapsGuestFeaturePtr feature; - if ((feature = calloc(1, sizeof(*feature))) == NULL) + if (VIR_ALLOC(feature) < 0) goto no_memory; if ((feature->name = strdup(name)) == NULL) @@ -393,11 +382,9 @@ virCapabilitiesAddGuestFeature(virCapsGuestPtr guest, feature->defaultOn = defaultOn; feature->toggle = toggle; - if ((features = realloc(guest->features, - sizeof(*features) * - (guest->nfeatures + 1))) == NULL) + if (VIR_REALLOC_N(guest->features, + guest->nfeatures + 1) < 0) goto no_memory; - guest->features = features; guest->features[guest->nfeatures] = feature; guest->nfeatures++; diff --git a/src/hash.c b/src/hash.c index 2cb60b2a61..4c11456f00 100644 --- a/src/hash.c +++ b/src/hash.c @@ -25,6 +25,7 @@ #include #include "internal.h" #include "hash.h" +#include "memory.h" #define MAX_HASH_LEN 8 @@ -85,22 +86,22 @@ virHashComputeKey(virHashTablePtr table, const char *name) virHashTablePtr virHashCreate(int size) { - virHashTablePtr table; + virHashTablePtr table = NULL; if (size <= 0) size = 256; - table = malloc(sizeof(*table)); - if (table) { - table->size = size; - table->nbElems = 0; - table->table = calloc(1, size * sizeof(*(table->table))); - if (table->table) { - return (table); - } - free(table); + if (VIR_ALLOC(table) < 0) + return NULL; + + table->size = size; + table->nbElems = 0; + if (VIR_ALLOC_N(table->table, size) < 0) { + VIR_FREE(table); + return NULL; } - return (NULL); + + return table; } /** @@ -136,8 +137,7 @@ virHashGrow(virHashTablePtr table, int size) if (oldtable == NULL) return (-1); - table->table = calloc(1, size * sizeof(*(table->table))); - if (table->table == NULL) { + if (VIR_ALLOC_N(table->table, size) < 0) { table->table = oldtable; return (-1); } @@ -170,7 +170,7 @@ virHashGrow(virHashTablePtr table, int size) if (table->table[key].valid == 0) { memcpy(&(table->table[key]), iter, sizeof(virHashEntry)); table->table[key].next = NULL; - free(iter); + VIR_FREE(iter); } else { iter->next = table->table[key].next; table->table[key].next = iter; @@ -184,7 +184,7 @@ virHashGrow(virHashTablePtr table, int size) } } - free(oldtable); + VIR_FREE(oldtable); #ifdef DEBUG_GROW xmlGenericError(xmlGenericErrorContext, @@ -225,19 +225,19 @@ virHashFree(virHashTablePtr table, virHashDeallocator f) next = iter->next; if ((f != NULL) && (iter->payload != NULL)) f(iter->payload, iter->name); - free(iter->name); + VIR_FREE(iter->name); iter->payload = NULL; if (!inside_table) - free(iter); + VIR_FREE(iter); nbElems--; inside_table = 0; iter = next; } inside_table = 0; } - free(table->table); + VIR_FREE(table->table); } - free(table); + VIR_FREE(table); } /** @@ -281,8 +281,7 @@ virHashAddEntry(virHashTablePtr table, const char *name, void *userdata) if (insert == NULL) { entry = &(table->table[key]); } else { - entry = malloc(sizeof(*entry)); - if (entry == NULL) + if (VIR_ALLOC(entry) < 0) return (-1); } @@ -354,8 +353,7 @@ virHashUpdateEntry(virHashTablePtr table, const char *name, if (insert == NULL) { entry = &(table->table[key]); } else { - entry = malloc(sizeof(*entry)); - if (entry == NULL) + if (VIR_ALLOC(entry) < 0) return (-1); } @@ -451,10 +449,10 @@ virHashRemoveEntry(virHashTablePtr table, const char *name, if ((f != NULL) && (entry->payload != NULL)) f(entry->payload, entry->name); entry->payload = NULL; - free(entry->name); + VIR_FREE(entry->name); if (prev) { prev->next = entry->next; - free(entry); + VIR_FREE(entry); } else { if (entry->next == NULL) { entry->valid = 0; @@ -462,7 +460,7 @@ virHashRemoveEntry(virHashTablePtr table, const char *name, entry = entry->next; memcpy(&(table->table[key]), entry, sizeof(virHashEntry)); - free(entry); + VIR_FREE(entry); } } table->nbElems--; @@ -535,11 +533,11 @@ int virHashRemoveSet(virHashTablePtr table, virHashSearcher iter, virHashDealloc if (iter(entry->payload, entry->name, data)) { count++; f(entry->payload, entry->name); - free(entry->name); + VIR_FREE(entry->name); table->nbElems--; if (prev) { prev->next = entry->next; - free(entry); + VIR_FREE(entry); entry = prev; } else { if (entry->next == NULL) { @@ -549,7 +547,7 @@ int virHashRemoveSet(virHashTablePtr table, virHashSearcher iter, virHashDealloc entry = entry->next; memcpy(&(table->table[i]), entry, sizeof(virHashEntry)); - free(entry); + VIR_FREE(entry); entry = &(table->table[i]); continue; } @@ -689,8 +687,7 @@ virConnectPtr virGetConnect(void) { virConnectPtr ret; - ret = calloc(1, sizeof(*ret)); - if (ret == NULL) { + if (VIR_ALLOC(ret) < 0) { virHashError(NULL, VIR_ERR_NO_MEMORY, _("allocating connection")); goto failed; } @@ -729,7 +726,7 @@ failed: virHashFree(ret->storageVols, (virHashDeallocator) virStorageVolFreeName); pthread_mutex_destroy(&ret->lock); - free(ret); + VIR_FREE(ret); } return(NULL); } @@ -759,11 +756,11 @@ virReleaseConnect(virConnectPtr conn) { if (__lastErr.conn == conn) __lastErr.conn = NULL; - free(conn->name); + VIR_FREE(conn->name); pthread_mutex_unlock(&conn->lock); pthread_mutex_destroy(&conn->lock); - free(conn); + VIR_FREE(conn); } /** @@ -824,8 +821,8 @@ __virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) ret = (virDomainPtr) virHashLookup(conn->domains, name); /* TODO check the UUID */ if (ret == NULL) { - ret = (virDomainPtr) calloc(1, sizeof(*ret)); - if (ret == NULL) { + VIR_ALLOC(ret); + if (0) { virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating domain")); goto error; } @@ -854,8 +851,8 @@ __virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) error: pthread_mutex_unlock(&conn->lock); if (ret != NULL) { - free(ret->name ); - free(ret); + VIR_FREE(ret->name); + VIR_FREE(ret); } return(NULL); } @@ -888,8 +885,8 @@ virReleaseDomain(virDomainPtr domain) { __lastErr.dom = NULL; domain->magic = -1; domain->id = -1; - free(domain->name); - free(domain); + VIR_FREE(domain->name); + VIR_FREE(domain); DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); conn->refs--; @@ -962,8 +959,7 @@ __virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) ret = (virNetworkPtr) virHashLookup(conn->networks, name); /* TODO check the UUID */ if (ret == NULL) { - ret = (virNetworkPtr) calloc(1, sizeof(*ret)); - if (ret == NULL) { + if (VIR_ALLOC(ret) < 0) { virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating network")); goto error; } @@ -991,8 +987,8 @@ __virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) error: pthread_mutex_unlock(&conn->lock); if (ret != NULL) { - free(ret->name ); - free(ret); + VIR_FREE(ret->name); + VIR_FREE(ret); } return(NULL); } @@ -1025,8 +1021,8 @@ virReleaseNetwork(virNetworkPtr network) { __lastErr.net = NULL; network->magic = -1; - free(network->name); - free(network); + VIR_FREE(network->name); + VIR_FREE(network); DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); conn->refs--; @@ -1100,8 +1096,7 @@ __virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *u ret = (virStoragePoolPtr) virHashLookup(conn->storagePools, name); /* TODO check the UUID */ if (ret == NULL) { - ret = (virStoragePoolPtr) calloc(1, sizeof(*ret)); - if (ret == NULL) { + if (VIR_ALLOC(ret) < 0) { virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating storage pool")); goto error; } @@ -1129,8 +1124,8 @@ __virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *u error: pthread_mutex_unlock(&conn->lock); if (ret != NULL) { - free(ret->name); - free(ret); + VIR_FREE(ret->name); + VIR_FREE(ret); } return(NULL); } @@ -1159,8 +1154,8 @@ virReleaseStoragePool(virStoragePoolPtr pool) { _("pool missing from connection hash table")); pool->magic = -1; - free(pool->name); - free(pool); + VIR_FREE(pool->name); + VIR_FREE(pool); DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); conn->refs--; @@ -1232,8 +1227,7 @@ __virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, const ret = (virStorageVolPtr) virHashLookup(conn->storageVols, key); if (ret == NULL) { - ret = (virStorageVolPtr) calloc(1, sizeof(*ret)); - if (ret == NULL) { + if (VIR_ALLOC(ret) < 0) { virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating storage vol")); goto error; } @@ -1266,9 +1260,9 @@ __virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, const error: pthread_mutex_unlock(&conn->lock); if (ret != NULL) { - free(ret->name); - free(ret->pool); - free(ret); + VIR_FREE(ret->name); + VIR_FREE(ret->pool); + VIR_FREE(ret); } return(NULL); } @@ -1297,9 +1291,9 @@ virReleaseStorageVol(virStorageVolPtr vol) { _("vol missing from connection hash table")); vol->magic = -1; - free(vol->name); - free(vol->pool); - free(vol); + VIR_FREE(vol->name); + VIR_FREE(vol->pool); + VIR_FREE(vol); DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); conn->refs--; diff --git a/src/internal.h b/src/internal.h index 02cd3584a1..7df866154e 100644 --- a/src/internal.h +++ b/src/internal.h @@ -78,7 +78,7 @@ extern int debugFlag; #define VIR_DEBUG(category, fmt,...) \ do { if (debugFlag) fprintf (stderr, "DEBUG: %s: %s (" fmt ")\n", category, __func__, __VA_ARGS__); } while (0) #else -#define VIR_DEBUG(category, fmt,...) +#define VIR_DEBUG(category, fmt,...) \ do { } while (0) #endif /* !ENABLE_DEBUG */ @@ -88,6 +88,11 @@ extern int debugFlag; #endif #ifdef __GNUC__ + +#ifndef __GNUC_PREREQ +#define __GNUC_PREREQ(maj,min) 0 +#endif + /** * ATTRIBUTE_UNUSED: * @@ -107,9 +112,18 @@ extern int debugFlag; #define ATTRIBUTE_FORMAT(args...) __attribute__((__format__ (args))) #endif +#ifndef ATTRIBUTE_RETURN_CHECK +#if __GNUC_PREREQ (3, 4) +#define ATTRIBUTE_RETURN_CHECK __attribute__((__warn_unused_result__)) +#else +#define ATTRIBUTE_RETURN_CHECK +#endif +#endif + #else #define ATTRIBUTE_UNUSED #define ATTRIBUTE_FORMAT(...) +#define ATTRIBUTE_RETURN_CHECK #endif /* __GNUC__ */ /** diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000000..fe41e383f4 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,140 @@ +/* + * memory.c: safer memory allocation + * + * Copyright (C) 2008 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include + +#include "memory.h" + + +/* Return 1 if an array of N objects, each of size S, cannot exist due + to size arithmetic overflow. S must be positive and N must be + nonnegative. This is a macro, not an inline function, so that it + works correctly even when SIZE_MAX < N. + + By gnulib convention, SIZE_MAX represents overflow in size + calculations, so the conservative dividend to use here is + SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value. + However, malloc (SIZE_MAX) fails on all known hosts where + sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for + exactly-SIZE_MAX allocations on such hosts; this avoids a test and + branch when S is known to be 1. */ +# define xalloc_oversized(n, s) \ + ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) + + +/** + * virAlloc: + * @ptrptr: pointer to pointer for address of allocated memory + * @size: number of bytes to allocate + * + * Allocate 'size' bytes of memory. Return the address of the + * allocated memory in 'ptrptr'. The newly allocated memory is + * filled with zeros. + * + * Returns -1 on failure to allocate, zero on success + */ +int virAlloc(void *ptrptr, size_t size) +{ + if (size == 0) { + *(void **)ptrptr = NULL; + return 0; + } + + + + *(void **)ptrptr = calloc(1, size); + if (*(void **)ptrptr == NULL) + return -1; + return 0; +} + +/** + * virAllocN: + * @ptrptr: pointer to pointer for address of allocated memory + * @size: number of bytes to allocate + * @count: number of elements to allocate + * + * Allocate an array of memory 'count' elements long, + * each with 'size' bytes. Return the address of the + * allocated memory in 'ptrptr'. The newly allocated + * memory is filled with zeros. + * + * Returns -1 on failure to allocate, zero on success + */ +int virAllocN(void *ptrptr, size_t size, size_t count) +{ + if (size == 0 || count == 0) { + *(void **)ptrptr = NULL; + return 0; + } + + *(void**)ptrptr = calloc(count, size); + if (*(void**)ptrptr == NULL) + return -1; + return 0; +} + +/** + * virReallocN: + * @ptrptr: pointer to pointer for address of allocated memory + * @size: number of bytes to allocate + * @count: number of elements in array + * + * Resize the block of memory in 'ptrptr' to be an array of + * 'count' elements, each 'size' bytes in length. Update 'ptrptr' + * with the address of the newly allocated memory. On failure, + * 'ptrptr' is not changed and still points to the original memory + * block. The newly allocated memory is filled with zeros. + * + * Returns -1 on failure to allocate, zero on success + */ +int virReallocN(void *ptrptr, size_t size, size_t count) +{ + void *tmp; + if (size == 0 || count == 0) { + free(*(void **)ptrptr); + *(void **)ptrptr = NULL; + return 0; + } + if (xalloc_oversized(count, size)) { + errno = ENOMEM; + return -1; + } + tmp = realloc(*(void**)ptrptr, size * count); + if (!tmp) + return -1; + *(void**)ptrptr = tmp; + return 0; +} + +/** + * virFree: + * @ptrptr: pointer to pointer for address of memory to be freed + * + * Release the chunk of memory in the pointer pointed to by + * the 'ptrptr' variable. After release, 'ptrptr' will be + * updated to point to NULL. + */ +void virFree(void *ptrptr) +{ + free(*(void**)ptrptr); + *(void**)ptrptr = NULL; +} diff --git a/src/memory.h b/src/memory.h new file mode 100644 index 0000000000..872fd8cc7a --- /dev/null +++ b/src/memory.h @@ -0,0 +1,82 @@ +/* + * memory.c: safer memory allocation + * + * Copyright (C) 2008 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#ifndef __VIR_MEMORY_H_ +#define __VIR_MEMORY_H_ + +#include "internal.h" + +/* Don't call these directly - use the macros below */ +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; +void virFree(void *ptrptr); + + +/** + * VIR_ALLOC: + * @ptr: pointer to hold address of allocated memory + * + * Allocate sizeof(*ptr) bytes of memory and store + * the address of allocated memory in 'ptr'. Fill the + * newly allocated memory with zeros. + * + * Returns -1 on failure, 0 on success + */ +#define VIR_ALLOC(ptr) virAlloc(&(ptr), sizeof(*(ptr))) + +/** + * VIR_ALLOC_N: + * @ptr: pointer to hold address of allocated memory + * @count: number of elements to allocate + * + * Allocate an array of 'count' elements, each sizeof(*ptr) + * bytes long and store the address of allocated memory in + * 'ptr'. Fill the newly allocated memory with zeros. + * + * Returns -1 on failure, 0 on success + */ +#define VIR_ALLOC_N(ptr, count) virAllocN(&(ptr), sizeof(*(ptr)), (count)) + +/** + * VIR_REALLOC_N: + * @ptr: pointer to hold address of allocated memory + * @count: number of elements to allocate + * + * Re-allocate an array of 'count' elements, each sizeof(*ptr) + * bytes long and store the address of allocated memory in + * 'ptr'. Fill the newly allocated memory with zeros + * + * Returns -1 on failure, 0 on success + */ +#define VIR_REALLOC_N(ptr, count) virReallocN(&(ptr), sizeof(*(ptr)), (count)) + +/** + * VIR_FREE: + * @ptr: pointer holding address to be freed + * + * Free the memory stored in 'ptr' and update to point + * to NULL. + */ +#define VIR_FREE(ptr) virFree(&(ptr)); + +#endif /* __VIR_MEMORY_H_ */ -- GitLab