util: use glib memory allocation functions

Convert the VIR_ALLOC family of APIs with use of the g_malloc family of
APIs. Use of VIR_ALLOC related functions should be incrementally phased
out over time, allowing return value checks to be dropped. Use of
VIR_FREE should be replaced with auto-cleanup whenever possible.

We previously used the 'calloc-posix' gnulib module because mingw does
not set errno to ENOMEM on failure.

Reviewed-by: Ján Tomko <jtomko@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2019-10-07 17:56:08 +01:00
parent cfbe9f1201
commit e85e34f3af
4 changed files with 27 additions and 118 deletions

View File

@ -26,7 +26,6 @@ byteswap
c-ctype
c-strcase
c-strcasestr
calloc-posix
canonicalize-lgpl
chown
clock-time

View File

@ -1008,102 +1008,20 @@ BAD:
</p>
<dl>
<dt>VIR_ALLOC, VIR_REALLOC, VIR_RESIZE_N, VIR_EXPAND_N,
VIR_SHRINK_N, VIR_FREE, VIR_APPEND_ELEMENT, VIR_INSERT_ELEMENT,
VIR_DELETE_ELEMENT</dt>
<dd>Prefer the GLib APIs g_new0/g_renew/g_free in most cases.
There should rarely be a need to use g_malloc/g_realloc.
Instead of using plain C arrays, it is preferrable to use
one of the GLib types, GArray, GPtrArray or GByteArray. These
all use a struct to track the array memory and size together
and efficiently resize. <strong>NEVER MIX</strong> use of the
classic libvirt memory allocation APIs and GLib APIs within
a single method. Keep the style consistent, converting existing
code to GLib style in a separate, prior commit.</dd>
</dl>
<h2><a id="memalloc">Low level memory management</a></h2>
<p>
Use of the malloc/free/realloc/calloc APIs is deprecated in the libvirt
codebase, because they encourage a number of serious coding bugs and do
not enable compile time verification of checks for NULL. Instead of these
routines, use the macros from viralloc.h.
</p>
<ul>
<li><p>To allocate a single object:</p>
<pre>
virDomainPtr domain;
if (VIR_ALLOC(domain) &lt; 0)
return NULL;
</pre>
</li>
<li><p>To allocate an array of objects:</p>
<pre>
virDomainPtr domains;
size_t ndomains = 10;
if (VIR_ALLOC_N(domains, ndomains) &lt; 0)
return NULL;
</pre>
</li>
<li><p>To allocate an array of object pointers:</p>
<pre>
virDomainPtr *domains;
size_t ndomains = 10;
if (VIR_ALLOC_N(domains, ndomains) &lt; 0)
return NULL;
</pre>
</li>
<li><p>To re-allocate the array of domains to be 1 element
longer (however, note that repeatedly expanding an array by 1
scales quadratically, so this is recommended only for smaller
arrays):</p>
<pre>
virDomainPtr domains;
size_t ndomains = 0;
if (VIR_EXPAND_N(domains, ndomains, 1) &lt; 0)
return NULL;
domains[ndomains - 1] = domain;
</pre></li>
<li><p>To ensure an array has room to hold at least one more
element (this approach scales better, but requires tracking
allocation separately from usage)</p>
<pre>
virDomainPtr domains;
size_t ndomains = 0;
size_t ndomains_max = 0;
if (VIR_RESIZE_N(domains, ndomains_max, ndomains, 1) &lt; 0)
return NULL;
domains[ndomains++] = domain;
</pre>
</li>
<li><p>To trim an array of domains from its allocated size down
to the actual used size:</p>
<pre>
virDomainPtr domains;
size_t ndomains = x;
size_t ndomains_max = y;
VIR_SHRINK_N(domains, ndomains_max, ndomains_max - ndomains);
</pre></li>
<li><p>To free an array of domains:</p>
<pre>
virDomainPtr domains;
size_t ndomains = x;
size_t ndomains_max = y;
size_t i;
for (i = 0; i &lt; ndomains; i++)
VIR_FREE(domains[i]);
VIR_FREE(domains);
ndomains_max = ndomains = 0;
</pre>
</li>
</ul>
<h2><a id="file_handling">File handling</a></h2>
<p>

View File

@ -45,10 +45,7 @@ VIR_LOG_INIT("util.alloc");
int virAlloc(void *ptrptr,
size_t size)
{
*(void **)ptrptr = calloc(1, size);
if (*(void **)ptrptr == NULL)
abort();
*(void **)ptrptr = g_malloc0(size);
return 0;
}
@ -69,10 +66,7 @@ int virAllocN(void *ptrptr,
size_t size,
size_t count)
{
*(void**)ptrptr = calloc(count, size);
if (*(void**)ptrptr == NULL)
abort();
*(void**)ptrptr = g_malloc0_n(count, size);
return 0;
}
@ -94,16 +88,7 @@ int virReallocN(void *ptrptr,
size_t size,
size_t count)
{
void *tmp;
if (xalloc_oversized(count, size))
abort();
tmp = realloc(*(void**)ptrptr, size * count);
if (!tmp && ((size * count) != 0))
abort();
*(void**)ptrptr = tmp;
*(void **)ptrptr = g_realloc_n(*(void**)ptrptr, size, count);
return 0;
}
@ -343,9 +328,7 @@ int virAllocVar(void *ptrptr,
abort();
alloc_size = struct_size + (element_size * count);
*(void **)ptrptr = calloc(1, alloc_size);
if (*(void **)ptrptr == NULL)
abort();
*(void **)ptrptr = g_malloc0(alloc_size);
return 0;
}
@ -362,7 +345,7 @@ void virFree(void *ptrptr)
{
int save_errno = errno;
free(*(void**)ptrptr);
g_free(*(void**)ptrptr);
*(void**)ptrptr = NULL;
errno = save_errno;
}
@ -395,7 +378,7 @@ void virDispose(void *ptrptr,
if (*(void**)ptrptr && count > 0)
memset(*(void **)ptrptr, 0, count * element_size);
free(*(void**)ptrptr);
g_free(*(void**)ptrptr);
*(void**)ptrptr = NULL;
if (countptr)

View File

@ -24,6 +24,15 @@
#include "internal.h"
/**
* DEPRECATION WARNING
*
* APIs in this file should only be used when modifying existing code.
* Consider converting existing code to use the new APIs when touching
* it. All new code must use the GLib memory allocation APIs and/or
* GLib array data types. See the hacking file for more guidance.
*/
/* 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