util: eliminate device object leaks related to virDomain*Remove*()

There are several functions in domain_conf.c that remove a device
object from the domain's list of that object type, but don't free the
object or return it to the caller to free. In many cases this isn't a
problem because the caller already had a pointer to the object and
frees it afterward, but in several cases the removed object was just
left floating around with no references to it.

In particular, the function qemuDomainDetachDeviceConfig() calls
functions to locate and remove net (virDomainNetRemoveByMac), disk
(virDomainDiskRemoveByName()), and lease (virDomainLeaseRemove())
devices, but neither it nor its caller qemuDomainModifyDeviceConfig()
ever obtain a pointer to the device being removed, much less free it.

This patch modifies the following "remove" functions to return a
pointer to the device object being removed from the domain device
arrays, to give the caller the option of freeing the device object
using that pointer if needed. In places where the object was
previously leaked, it is now freed:

  virDomainDiskRemove
  virDomainDiskRemoveByName
  virDomainNetRemove
  virDomainNetRemoveByMac
  virDomainHostdevRemove
  virDomainLeaseRemove
  virDomainLeaseRemoveAt

The functions that had been leaking:

  libxlDomainDetachConfig - leaked a virDomainDiskDef
  qemuDomainDetachDeviceConfig - could leak a virDomainDiskDef,
                            a virDomainNetDef, or a
                            virDomainLeaseDef
  qemuDomainDetachLease   - leaked a virDomainLeaseDef
This commit is contained in:
Laine Stump 2012-03-06 18:06:14 -05:00
parent b59e59845f
commit f985773d06
5 changed files with 61 additions and 34 deletions

View File

@ -6856,9 +6856,11 @@ virDomainHostdevInsert(virDomainDefPtr def, virDomainHostdevDefPtr hostdev)
return 0; return 0;
} }
void virDomainHostdevDefPtr
virDomainHostdevRemove(virDomainDefPtr def, size_t i) virDomainHostdevRemove(virDomainDefPtr def, size_t i)
{ {
virDomainHostdevDefPtr hostdev = def->hostdevs[i];
if (def->nhostdevs > 1) { if (def->nhostdevs > 1) {
memmove(def->hostdevs + i, memmove(def->hostdevs + i,
def->hostdevs + i + 1, def->hostdevs + i + 1,
@ -6872,6 +6874,7 @@ virDomainHostdevRemove(virDomainDefPtr def, size_t i)
VIR_FREE(def->hostdevs); VIR_FREE(def->hostdevs);
def->nhostdevs = 0; def->nhostdevs = 0;
} }
return hostdev;
} }
/* Find an entry in hostdevs that matches the source spec in /* Find an entry in hostdevs that matches the source spec in
@ -7035,8 +7038,11 @@ void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
} }
void virDomainDiskRemove(virDomainDefPtr def, size_t i) virDomainDiskDefPtr
virDomainDiskRemove(virDomainDefPtr def, size_t i)
{ {
virDomainDiskDefPtr disk = disk = def->disks[i];
if (def->ndisks > 1) { if (def->ndisks > 1) {
memmove(def->disks + i, memmove(def->disks + i,
def->disks + i + 1, def->disks + i + 1,
@ -7050,15 +7056,16 @@ void virDomainDiskRemove(virDomainDefPtr def, size_t i)
VIR_FREE(def->disks); VIR_FREE(def->disks);
def->ndisks = 0; def->ndisks = 0;
} }
return disk;
} }
int virDomainDiskRemoveByName(virDomainDefPtr def, const char *name) virDomainDiskDefPtr
virDomainDiskRemoveByName(virDomainDefPtr def, const char *name)
{ {
int i = virDomainDiskIndexByName(def, name, false); int i = virDomainDiskIndexByName(def, name, false);
if (i < 0) if (i < 0)
return -1; return NULL;
virDomainDiskRemove(def, i); return virDomainDiskRemove(def, i);
return 0;
} }
int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net) int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net)
@ -7084,7 +7091,8 @@ int virDomainNetIndexByMac(virDomainDefPtr def, const unsigned char *mac)
return -1; return -1;
} }
void virDomainNetRemove(virDomainDefPtr def, size_t i) virDomainNetDefPtr
virDomainNetRemove(virDomainDefPtr def, size_t i)
{ {
virDomainNetDefPtr net = def->nets[i]; virDomainNetDefPtr net = def->nets[i];
@ -7115,16 +7123,17 @@ void virDomainNetRemove(virDomainDefPtr def, size_t i)
VIR_FREE(def->nets); VIR_FREE(def->nets);
def->nnets = 0; def->nnets = 0;
} }
return net;
} }
int virDomainNetRemoveByMac(virDomainDefPtr def, const unsigned char *mac) virDomainNetDefPtr
virDomainNetRemoveByMac(virDomainDefPtr def, const unsigned char *mac)
{ {
int i = virDomainNetIndexByMac(def, mac); int i = virDomainNetIndexByMac(def, mac);
if (i < 0) if (i < 0)
return -1; return NULL;
virDomainNetRemove(def, i); return virDomainNetRemove(def, i);
return 0;
} }
@ -7233,8 +7242,12 @@ void virDomainLeaseInsertPreAlloced(virDomainDefPtr def,
} }
void virDomainLeaseRemoveAt(virDomainDefPtr def, size_t i) virDomainLeaseDefPtr
virDomainLeaseRemoveAt(virDomainDefPtr def, size_t i)
{ {
virDomainLeaseDefPtr lease = def->leases[i];
if (def->nleases > 1) { if (def->nleases > 1) {
memmove(def->leases + i, memmove(def->leases + i,
def->leases + i + 1, def->leases + i + 1,
@ -7245,17 +7258,18 @@ void virDomainLeaseRemoveAt(virDomainDefPtr def, size_t i)
VIR_FREE(def->leases); VIR_FREE(def->leases);
def->nleases = 0; def->nleases = 0;
} }
return lease;
} }
int virDomainLeaseRemove(virDomainDefPtr def, virDomainLeaseDefPtr
virDomainLeaseDefPtr lease) virDomainLeaseRemove(virDomainDefPtr def,
virDomainLeaseDefPtr lease)
{ {
int i = virDomainLeaseIndex(def, lease); int i = virDomainLeaseIndex(def, lease);
if (i < 0) if (i < 0)
return -1; return NULL;
virDomainLeaseRemoveAt(def, i); return virDomainLeaseRemoveAt(def, i);
return 0;
} }

View File

@ -1901,16 +1901,21 @@ void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
virDomainDiskDefPtr disk); virDomainDiskDefPtr disk);
int virDomainDiskDefAssignAddress(virCapsPtr caps, virDomainDiskDefPtr def); int virDomainDiskDefAssignAddress(virCapsPtr caps, virDomainDiskDefPtr def);
void virDomainDiskRemove(virDomainDefPtr def, size_t i); virDomainDiskDefPtr
int virDomainDiskRemoveByName(virDomainDefPtr def, const char *name); virDomainDiskRemove(virDomainDefPtr def, size_t i);
virDomainDiskDefPtr
virDomainDiskRemoveByName(virDomainDefPtr def, const char *name);
int virDomainNetIndexByMac(virDomainDefPtr def, const unsigned char *mac); int virDomainNetIndexByMac(virDomainDefPtr def, const unsigned char *mac);
int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net); int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net);
void virDomainNetRemove(virDomainDefPtr def, size_t i); virDomainNetDefPtr
int virDomainNetRemoveByMac(virDomainDefPtr def, const unsigned char *mac); virDomainNetRemove(virDomainDefPtr def, size_t i);
virDomainNetDefPtr
virDomainNetRemoveByMac(virDomainDefPtr def, const unsigned char *mac);
int virDomainHostdevInsert(virDomainDefPtr def, virDomainHostdevDefPtr hostdev); int virDomainHostdevInsert(virDomainDefPtr def, virDomainHostdevDefPtr hostdev);
void virDomainHostdevRemove(virDomainDefPtr def, size_t i); virDomainHostdevDefPtr
virDomainHostdevRemove(virDomainDefPtr def, size_t i);
int virDomainHostdevFind(virDomainDefPtr def, virDomainHostdevDefPtr match, int virDomainHostdevFind(virDomainDefPtr def, virDomainHostdevDefPtr match,
virDomainHostdevDefPtr *found); virDomainHostdevDefPtr *found);
@ -1955,9 +1960,11 @@ int virDomainLeaseInsert(virDomainDefPtr def,
int virDomainLeaseInsertPreAlloc(virDomainDefPtr def); int virDomainLeaseInsertPreAlloc(virDomainDefPtr def);
void virDomainLeaseInsertPreAlloced(virDomainDefPtr def, void virDomainLeaseInsertPreAlloced(virDomainDefPtr def,
virDomainLeaseDefPtr lease); virDomainLeaseDefPtr lease);
void virDomainLeaseRemoveAt(virDomainDefPtr def, size_t i); virDomainLeaseDefPtr
int virDomainLeaseRemove(virDomainDefPtr def, virDomainLeaseRemoveAt(virDomainDefPtr def, size_t i);
virDomainLeaseDefPtr lease); virDomainLeaseDefPtr
virDomainLeaseRemove(virDomainDefPtr def,
virDomainLeaseDefPtr lease);
int virDomainSaveXML(const char *configDir, int virDomainSaveXML(const char *configDir,
virDomainDefPtr def, virDomainDefPtr def,

View File

@ -3089,17 +3089,18 @@ libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm,
static int static int
libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{ {
virDomainDiskDefPtr disk; virDomainDiskDefPtr disk, detach;
int ret = -1; int ret = -1;
switch (dev->type) { switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK: case VIR_DOMAIN_DEVICE_DISK:
disk = dev->data.disk; disk = dev->data.disk;
if (virDomainDiskRemoveByName(vmdef, disk->dst)) { if (!(detach = virDomainDiskRemoveByName(vmdef, disk->dst))) {
libxlError(VIR_ERR_INVALID_ARG, libxlError(VIR_ERR_INVALID_ARG,
_("no target device %s"), disk->dst); _("no target device %s"), disk->dst);
break; break;
} }
virDomainDiskDefFree(detach);
ret = 0; ret = 0;
break; break;
default: default:

View File

@ -5436,23 +5436,24 @@ static int
qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef, qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
virDomainDeviceDefPtr dev) virDomainDeviceDefPtr dev)
{ {
virDomainDiskDefPtr disk; virDomainDiskDefPtr disk, det_disk;
virDomainNetDefPtr net; virDomainNetDefPtr net, det_net;
virDomainLeaseDefPtr lease; virDomainLeaseDefPtr lease, det_lease;
switch (dev->type) { switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK: case VIR_DOMAIN_DEVICE_DISK:
disk = dev->data.disk; disk = dev->data.disk;
if (virDomainDiskRemoveByName(vmdef, disk->dst)) { if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
qemuReportError(VIR_ERR_INVALID_ARG, qemuReportError(VIR_ERR_INVALID_ARG,
_("no target device %s"), disk->dst); _("no target device %s"), disk->dst);
return -1; return -1;
} }
virDomainDiskDefFree(det_disk);
break; break;
case VIR_DOMAIN_DEVICE_NET: case VIR_DOMAIN_DEVICE_NET:
net = dev->data.net; net = dev->data.net;
if (virDomainNetRemoveByMac(vmdef, net->mac)) { if (!(det_net = virDomainNetRemoveByMac(vmdef, net->mac))) {
char macbuf[VIR_MAC_STRING_BUFLEN]; char macbuf[VIR_MAC_STRING_BUFLEN];
virMacAddrFormat(net->mac, macbuf); virMacAddrFormat(net->mac, macbuf);
@ -5460,16 +5461,18 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
_("no nic of mac %s"), macbuf); _("no nic of mac %s"), macbuf);
return -1; return -1;
} }
virDomainNetDefFree(det_net);
break; break;
case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_LEASE:
lease = dev->data.lease; lease = dev->data.lease;
if (virDomainLeaseRemove(vmdef, lease) < 0) { if (!(det_lease = virDomainLeaseRemove(vmdef, lease))) {
qemuReportError(VIR_ERR_INVALID_ARG, qemuReportError(VIR_ERR_INVALID_ARG,
_("Lease %s in lockspace %s does not exist"), _("Lease %s in lockspace %s does not exist"),
lease->key, NULLSTR(lease->lockspace)); lease->key, NULLSTR(lease->lockspace));
return -1; return -1;
} }
virDomainLeaseDefFree(det_lease);
break; break;
default: default:

View File

@ -2286,6 +2286,7 @@ int qemuDomainDetachLease(struct qemud_driver *driver,
virDomainObjPtr vm, virDomainObjPtr vm,
virDomainLeaseDefPtr lease) virDomainLeaseDefPtr lease)
{ {
virDomainLeaseDefPtr det_lease;
int i; int i;
if ((i = virDomainLeaseIndex(vm->def, lease)) < 0) { if ((i = virDomainLeaseIndex(vm->def, lease)) < 0) {
@ -2298,6 +2299,7 @@ int qemuDomainDetachLease(struct qemud_driver *driver,
if (virDomainLockLeaseDetach(driver->lockManager, vm, lease) < 0) if (virDomainLockLeaseDetach(driver->lockManager, vm, lease) < 0)
return -1; return -1;
virDomainLeaseRemoveAt(vm->def, i); det_lease = virDomainLeaseRemoveAt(vm->def, i);
virDomainLeaseDefFree(det_lease);
return 0; return 0;
} }