libvirt/src/datatypes.c

829 lines
21 KiB
C
Raw Normal View History

/*
* datatypes.h: management of structs for public data types
*
* Copyright (C) 2006-2014 Red Hat, Inc.
*
* 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, see
* <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include <unistd.h>
#include "datatypes.h"
#include "virerror.h"
2012-12-12 17:59:27 +00:00
#include "virlog.h"
2012-12-12 18:06:53 +00:00
#include "viralloc.h"
2012-12-13 18:01:25 +00:00
#include "viruuid.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_NONE
#define virLibConnError(code, ...) \
virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \
build: consistently use C99 varargs macros Prior to this patch, there was an inconsistent mix between GNU and C99. For consistency, and potential portability to other compilers, stick with the C99 vararg macro syntax. * src/conf/cpu_conf.c (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/conf/domain_conf.c (virDomainReportError): Likewise. * src/conf/domain_event.c (eventReportError): Likewise. * src/conf/interface_conf.c (virInterfaceReportError): Likewise. * src/conf/network_conf.c (virNetworkReportError): Likewise. * src/conf/node_device_conf.h (virNodeDeviceReportError): Likewise. * src/conf/secret_conf.h (virSecretReportError): Likewise. * src/conf/storage_conf.h (virStorageReportError): Likewise. * src/esx/esx_device_monitor.c (ESX_ERROR): Use C99 rather than GNU vararg macro syntax. * src/esx/esx_driver.c (ESX_ERROR): Likewise. * src/esx/esx_interface_driver.c (ESX_ERROR): Likewise. * src/esx/esx_network_driver.c (ESX_ERROR): Likewise. * src/esx/esx_secret_driver.c (ESX_ERROR): Likewise. * src/esx/esx_storage_driver.c (ESX_ERROR): Likewise. * src/esx/esx_util.c (ESX_ERROR): Likewise. * src/esx/esx_vi.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_methods.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_types.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vmx.c (ESX_ERROR): Likewise. * src/util/hostusb.c (usbReportError): Use C99 rather than GNU vararg macro syntax. * src/util/json.c (virJSONError): Likewise. * src/util/macvtap.c (ReportError): Likewise. * src/util/pci.c (pciReportError): Likewise. * src/util/stats_linux.c (virStatsError): Likewise. * src/util/util.c (virUtilError): Likewise. * src/util/xml.c (virXMLError): Likewise. * src/xen/proxy_internal.c (virProxyError): Use C99 rather than GNU vararg macro syntax. * src/xen/sexpr.c (virSexprError): Likewise. * src/xen/xen_driver.c (xenUnifiedError): Likewise. * src/xen/xen_hypervisor.c (virXenError): Likewise. * src/xen/xen_inotify.c (virXenInotifyError): Likewise. * src/xen/xend_internal.c (virXendError): Likewise. * src/xen/xm_internal.c (xenXMError): Likewise. * src/xen/xs_internal.c (virXenStoreError): Likewise. * src/cpu/cpu.h (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/datatypes.c (virLibConnError): Likewise. * src/interface/netcf_driver.c (interfaceReportError): Likewise. * src/libvirt.c (virLibStreamError): Likewise. * src/lxc/lxc_conf.h (lxcError): Likewise. * src/network/bridge_driver.c (networkReportError): Likewise. * src/nodeinfo.c (nodeReportError): Likewise. * src/opennebula/one_conf.h (oneError): Likewise. * src/openvz/openvz_conf.h (openvzError): Likewise. * src/phyp/phyp_driver.c (PHYP_ERROR): Likewise. * src/qemu/qemu_conf.h (qemuReportError): Likewise. * src/remote/remote_driver.c (errorf): Likewise. * src/security/security_driver.h (virSecurityReportError): Likewise. * src/test/test_driver.c (testError): Likewise. * src/uml/uml_conf.h (umlReportError): Likewise. * src/vbox/vbox_driver.c (vboxError): Likewise. * src/vbox/vbox_tmpl.c (vboxError): Likewise.
2010-03-01 23:38:28 +00:00
__FUNCTION__, __LINE__, __VA_ARGS__)
2009-04-01 10:31:01 +00:00
virClassPtr virConnectClass;
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
virClassPtr virConnectCloseCallbackDataClass;
virClassPtr virDomainClass;
virClassPtr virDomainSnapshotClass;
virClassPtr virInterfaceClass;
virClassPtr virNetworkClass;
virClassPtr virNodeDeviceClass;
virClassPtr virNWFilterClass;
virClassPtr virSecretClass;
virClassPtr virStreamClass;
virClassPtr virStorageVolClass;
virClassPtr virStoragePoolClass;
static void virConnectDispose(void *obj);
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
static void virConnectCloseCallbackDataDispose(void *obj);
static void virDomainDispose(void *obj);
static void virDomainSnapshotDispose(void *obj);
static void virInterfaceDispose(void *obj);
static void virNetworkDispose(void *obj);
static void virNodeDeviceDispose(void *obj);
static void virNWFilterDispose(void *obj);
static void virSecretDispose(void *obj);
static void virStreamDispose(void *obj);
static void virStorageVolDispose(void *obj);
static void virStoragePoolDispose(void *obj);
static int
virDataTypesOnceInit(void)
{
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
#define DECLARE_CLASS_COMMON(basename, parent) \
if (!(basename ## Class = virClassNew(parent, \
#basename, \
sizeof(basename), \
basename ## Dispose))) \
return -1;
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
#define DECLARE_CLASS(basename) \
DECLARE_CLASS_COMMON(basename, virClassForObject())
#define DECLARE_CLASS_LOCKABLE(basename) \
DECLARE_CLASS_COMMON(basename, virClassForObjectLockable())
DECLARE_CLASS(virConnect);
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
DECLARE_CLASS_LOCKABLE(virConnectCloseCallbackData);
DECLARE_CLASS(virDomain);
DECLARE_CLASS(virDomainSnapshot);
DECLARE_CLASS(virInterface);
DECLARE_CLASS(virNetwork);
DECLARE_CLASS(virNodeDevice);
DECLARE_CLASS(virNWFilter);
DECLARE_CLASS(virSecret);
DECLARE_CLASS(virStream);
DECLARE_CLASS(virStorageVol);
DECLARE_CLASS(virStoragePool);
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
#undef DECLARE_CLASS_COMMON
#undef DECLARE_CLASS_LOCKABLE
#undef DECLARE_CLASS
return 0;
}
VIR_ONCE_GLOBAL_INIT(virDataTypes)
/**
* virGetConnect:
*
* Allocates a new hypervisor connection structure
*
* Returns a new pointer or NULL in case of error.
*/
virConnectPtr
virGetConnect(void)
{
virConnectPtr ret;
if (virDataTypesInitialize() < 0)
return NULL;
if (!(ret = virObjectNew(virConnectClass)))
return NULL;
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
if (!(ret->closeCallback = virObjectNew(virConnectCloseCallbackDataClass)))
goto error;
if (virMutexInit(&ret->lock) < 0)
goto error;
2009-01-15 19:56:05 +00:00
return ret;
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
error:
virObjectUnref(ret);
return NULL;
}
/**
* virConnectDispose:
* @conn: the hypervisor connection to release
*
* Unconditionally release all memory associated with a connection.
* The conn.lock mutex must be held prior to calling this, and will
* be released prior to this returning. The connection obj must not
* be used once this method returns.
*/
static void
virConnectDispose(void *obj)
{
virConnectPtr conn = obj;
if (conn->networkDriver)
conn->networkDriver->networkClose(conn);
if (conn->interfaceDriver)
conn->interfaceDriver->interfaceClose(conn);
if (conn->storageDriver)
conn->storageDriver->storageClose(conn);
if (conn->nodeDeviceDriver)
conn->nodeDeviceDriver->nodeDeviceClose(conn);
if (conn->secretDriver)
conn->secretDriver->secretClose(conn);
if (conn->nwfilterDriver)
conn->nwfilterDriver->nwfilterClose(conn);
if (conn->driver)
conn->driver->connectClose(conn);
virMutexLock(&conn->lock);
virResetError(&conn->err);
virURIFree(conn->uri);
if (conn->closeCallback) {
virObjectLock(conn->closeCallback);
conn->closeCallback->callback = NULL;
virObjectUnlock(conn->closeCallback);
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
virObjectUnref(conn->closeCallback);
}
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
2009-01-15 19:56:05 +00:00
virMutexUnlock(&conn->lock);
virMutexDestroy(&conn->lock);
}
rpc: Fix connection close callback race condition and memory corruption/crash The last Viktor's effort to fix the race and memory corruption unfortunately wasn't complete in the case the close callback was not registered in an connection. At that time, the trail of event's that I'll describe later could still happen and corrupt the memory or cause a crash of the client (including the daemon in case of a p2p migration). Consider the following prerequisities and trail of events: Let's have a remote connection to a hypervisor that doesn't have a close callback registered and the client is using the event loop. The crash happens in cooperation of 2 threads. Thread E is the event loop and thread W is the worker that does some stuff. R denotes the remote client. 1.) W - The client finishes everything and sheds the last reference on the client 2.) W - The virObject stuff invokes virConnectDispose that invokes doRemoteClose 3.) W - the remote close method invokes the REMOTE_PROC_CLOSE RPC method. 4.) W - The thread is preempted at this point. 5.) R - The remote side receives the close and closes the socket. 6.) E - poll() wakes up due to the closed socket and invokes the close callback 7.) E - The event loop is preempted right before remoteClientCloseFunc is called 8.) W - The worker now finishes, and frees the conn object. 9.) E - The remoteClientCloseFunc accesses the now-freed conn object in the attempt to retrieve pointer for the real close callback. 10.) Kaboom, corrupted memory/segfault. This patch tries to fix this by introducing a new object that survives the freeing of the connection object. We can't increase the reference count on the connection object itself or the connection would never be closed, as the connection is closed only when the reference count reaches zero. The new object - virConnectCloseCallbackData - is a lockable object that keeps the pointers to the real user registered callback and ensures that the connection callback is either not called if the connection was already freed or that the connection isn't freed while this is being called.
2013-03-29 17:21:19 +00:00
/**
* virConnectCloseCallbackDataDispose:
* @obj: the close callback data to release
*
* Release resources bound to the connection close callback.
*/
static void
virConnectCloseCallbackDataDispose(void *obj)
{
virConnectCloseCallbackDataPtr cb = obj;
virObjectLock(cb);
if (cb->freeCallback)
cb->freeCallback(cb->opaque);
virObjectUnlock(cb);
}
/**
* virGetDomain:
* @conn: the hypervisor connection
* @name: pointer to the domain name
* @uuid: pointer to the uuid
*
* Lookup if the domain is already registered for that connection,
* if yes return a new pointer to it, if no allocate a new structure,
* and register it in the table. In any case a corresponding call to
* virObjectUnref() is needed to not leak data.
*
* Returns a pointer to the domain, or NULL in case of failure
*/
virDomainPtr
virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid)
{
virDomainPtr ret = NULL;
if (virDataTypesInitialize() < 0)
return NULL;
virCheckConnectGoto(conn, error);
virCheckNonNullArgGoto(name, error);
virCheckNonNullArgGoto(uuid, error);
if (!(ret = virObjectNew(virDomainClass)))
goto error;
if (VIR_STRDUP(ret->name, name) < 0)
goto error;
ret->conn = virObjectRef(conn);
ret->id = -1;
memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN);
return ret;
error:
virObjectUnref(ret);
return NULL;
}
/**
* virDomainDispose:
* @domain: the domain to release
*
* Unconditionally release all memory associated with a domain.
* The conn.lock mutex must be held prior to calling this, and will
* be released prior to this returning. The domain obj must not
* be used once this method returns.
*
* It will also unreference the associated connection object,
* which may also be released if its ref count hits zero.
*/
static void
virDomainDispose(void *obj)
{
virDomainPtr domain = obj;
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(domain->uuid, uuidstr);
VIR_DEBUG("release domain %p %s %s", domain, domain->name, uuidstr);
VIR_FREE(domain->name);
virObjectUnref(domain->conn);
}
/**
* virGetNetwork:
* @conn: the hypervisor connection
* @name: pointer to the network name
* @uuid: pointer to the uuid
*
* Lookup if the network is already registered for that connection,
* if yes return a new pointer to it, if no allocate a new structure,
* and register it in the table. In any case a corresponding call to
* virObjectUnref() is needed to not leak data.
*
* Returns a pointer to the network, or NULL in case of failure
*/
virNetworkPtr
virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid)
{
virNetworkPtr ret = NULL;
if (virDataTypesInitialize() < 0)
return NULL;
virCheckConnectGoto(conn, error);
virCheckNonNullArgGoto(name, error);
virCheckNonNullArgGoto(uuid, error);
if (!(ret = virObjectNew(virNetworkClass)))
goto error;
if (VIR_STRDUP(ret->name, name) < 0)
goto error;
ret->conn = virObjectRef(conn);
memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN);
return ret;
error:
virObjectUnref(ret);
return NULL;
}
/**
* virNetworkDispose:
* @network: the network to release
*
* Unconditionally release all memory associated with a network.
* The conn.lock mutex must be held prior to calling this, and will
* be released prior to this returning. The network obj must not
* be used once this method returns.
*
* It will also unreference the associated connection object,
* which may also be released if its ref count hits zero.
*/
static void
virNetworkDispose(void *obj)
{
virNetworkPtr network = obj;
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(network->uuid, uuidstr);
VIR_DEBUG("release network %p %s %s", network, network->name, uuidstr);
VIR_FREE(network->name);
virObjectUnref(network->conn);
}
/**
* virGetInterface:
* @conn: the hypervisor connection
* @name: pointer to the interface name
* @mac: pointer to the mac
*
* Lookup if the interface is already registered for that connection,
* if yes return a new pointer to it (possibly updating the MAC
* address), if no allocate a new structure, and register it in the
* table. In any case a corresponding call to virObjectUnref() is
* needed to not leak data.
*
* Returns a pointer to the interface, or NULL in case of failure
*/
virInterfacePtr
virGetInterface(virConnectPtr conn, const char *name, const char *mac)
{
virInterfacePtr ret = NULL;
if (virDataTypesInitialize() < 0)
return NULL;
virCheckConnectGoto(conn, error);
virCheckNonNullArgGoto(name, error);
/* a NULL mac from caller is okay. Treat it as blank */
if (mac == NULL)
mac = "";
if (!(ret = virObjectNew(virInterfaceClass)))
goto error;
if (VIR_STRDUP(ret->name, name) < 0 ||
VIR_STRDUP(ret->mac, mac) < 0)
goto error;
ret->conn = virObjectRef(conn);
return ret;
error:
virObjectUnref(ret);
return NULL;
}
/**
* virInterfaceDispose:
* @interface: the interface to release
*
2009-10-26 23:02:46 +00:00
* Unconditionally release all memory associated with an interface.
* The conn.lock mutex must be held prior to calling this, and will
* be released prior to this returning. The interface obj must not
* be used once this method returns.
*
* It will also unreference the associated connection object,
* which may also be released if its ref count hits zero.
*/
static void
virInterfaceDispose(void *obj)
{
virInterfacePtr iface = obj;
VIR_DEBUG("release interface %p %s", iface, iface->name);
VIR_FREE(iface->name);
VIR_FREE(iface->mac);
virObjectUnref(iface->conn);
}
/**
* virGetStoragePool:
* @conn: the hypervisor connection
* @name: pointer to the storage pool name
* @uuid: pointer to the uuid
* @privateData: pointer to driver specific private data
* @freeFunc: private data cleanup function pointer specfic to driver
*
* Lookup if the storage pool is already registered for that connection,
* if yes return a new pointer to it, if no allocate a new structure,
* and register it in the table. In any case a corresponding call to
* virObjectUnref() is needed to not leak data.
*
* Returns a pointer to the storage pool, or NULL in case of failure
*/
virStoragePoolPtr
virGetStoragePool(virConnectPtr conn, const char *name,
const unsigned char *uuid,
void *privateData, virFreeCallback freeFunc)
{
virStoragePoolPtr ret = NULL;
if (virDataTypesInitialize() < 0)
return NULL;
virCheckConnectGoto(conn, error);
virCheckNonNullArgGoto(name, error);
virCheckNonNullArgGoto(uuid, error);
if (!(ret = virObjectNew(virStoragePoolClass)))
goto error;
if (VIR_STRDUP(ret->name, name) < 0)
goto error;
ret->conn = virObjectRef(conn);
memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN);
/* set the driver specific data */
ret->privateData = privateData;
ret->privateDataFreeFunc = freeFunc;
return ret;
error:
virObjectUnref(ret);
return NULL;
}
/**
* virStoragePoolDispose:
* @pool: the pool to release
*
* Unconditionally release all memory associated with a pool.
* The conn.lock mutex must be held prior to calling this, and will
* be released prior to this returning. The pool obj must not
* be used once this method returns.
*
* It will also unreference the associated connection object,
* which may also be released if its ref count hits zero.
*/
static void
virStoragePoolDispose(void *obj)
{
virStoragePoolPtr pool = obj;
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(pool->uuid, uuidstr);
VIR_DEBUG("release pool %p %s %s", pool, pool->name, uuidstr);
if (pool->privateDataFreeFunc) {
pool->privateDataFreeFunc(pool->privateData);
}
VIR_FREE(pool->name);
virObjectUnref(pool->conn);
}
/**
* virGetStorageVol:
* @conn: the hypervisor connection
* @pool: pool owning the volume
* @name: pointer to the storage vol name
* @key: pointer to unique key of the volume
* @privateData: pointer to driver specific private data
* @freeFunc: private data cleanup function pointer specfic to driver
*
* Lookup if the storage vol is already registered for that connection,
* if yes return a new pointer to it, if no allocate a new structure,
* and register it in the table. In any case a corresponding call to
* virObjectUnref() is needed to not leak data.
*
* Returns a pointer to the storage vol, or NULL in case of failure
*/
virStorageVolPtr
virGetStorageVol(virConnectPtr conn, const char *pool, const char *name,
const char *key, void *privateData, virFreeCallback freeFunc)
{
virStorageVolPtr ret = NULL;
if (virDataTypesInitialize() < 0)
return NULL;
virCheckConnectGoto(conn, error);
virCheckNonNullArgGoto(pool, error);
virCheckNonNullArgGoto(name, error);
virCheckNonNullArgGoto(key, error);
if (!(ret = virObjectNew(virStorageVolClass)))
goto error;
if (VIR_STRDUP(ret->pool, pool) < 0 ||
VIR_STRDUP(ret->name, name) < 0 ||
VIR_STRDUP(ret->key, key) < 0)
goto error;
ret->conn = virObjectRef(conn);
/* set driver specific data */
ret->privateData = privateData;
ret->privateDataFreeFunc = freeFunc;
return ret;
error:
virObjectUnref(ret);
return NULL;
}
/**
* virStorageVolDispose:
* @vol: the vol to release
*
* Unconditionally release all memory associated with a vol.
* The conn.lock mutex must be held prior to calling this, and will
* be released prior to this returning. The vol obj must not
* be used once this method returns.
*
* It will also unreference the associated connection object,
* which may also be released if its ref count hits zero.
*/
static void
virStorageVolDispose(void *obj)
{
virStorageVolPtr vol = obj;
VIR_DEBUG("release vol %p %s", vol, vol->name);
if (vol->privateDataFreeFunc) {
vol->privateDataFreeFunc(vol->privateData);
}
VIR_FREE(vol->key);
VIR_FREE(vol->name);
VIR_FREE(vol->pool);
virObjectUnref(vol->conn);
}
/**
* virGetNodeDevice:
* @conn: the hypervisor connection
* @name: device name (unique on node)
*
* Lookup if the device is already registered for that connection,
* if yes return a new pointer to it, if no allocate a new structure,
* and register it in the table. In any case a corresponding call to
* virObjectUnref() is needed to not leak data.
*
* Returns a pointer to the node device, or NULL in case of failure
*/
virNodeDevicePtr
virGetNodeDevice(virConnectPtr conn, const char *name)
{
virNodeDevicePtr ret = NULL;
if (virDataTypesInitialize() < 0)
return NULL;
virCheckConnectGoto(conn, error);
virCheckNonNullArgGoto(name, error);
if (!(ret = virObjectNew(virNodeDeviceClass)))
goto error;
if (VIR_STRDUP(ret->name, name) < 0)
goto error;
ret->conn = virObjectRef(conn);
return ret;
error:
virObjectUnref(ret);
return NULL;
}
/**
* virNodeDeviceDispose:
* @dev: the dev to release
*
* Unconditionally release all memory associated with a dev.
* The conn.lock mutex must be held prior to calling this, and will
* be released prior to this returning. The dev obj must not
* be used once this method returns.
*
* It will also unreference the associated connection object,
* which may also be released if its ref count hits zero.
*/
static void
virNodeDeviceDispose(void *obj)
{
virNodeDevicePtr dev = obj;
VIR_DEBUG("release dev %p %s", dev, dev->name);
VIR_FREE(dev->name);
VIR_FREE(dev->parent);
virObjectUnref(dev->conn);
}
/**
* virGetSecret:
* @conn: the hypervisor connection
* @uuid: secret UUID
*
* Lookup if the secret is already registered for that connection, if so return
* a pointer to it, otherwise allocate a new structure, and register it in the
* table. In any case a corresponding call to virObjectUnref() is needed to not
* leak data.
*
* Returns a pointer to the secret, or NULL in case of failure
*/
virSecretPtr
virGetSecret(virConnectPtr conn, const unsigned char *uuid,
int usageType, const char *usageID)
{
virSecretPtr ret = NULL;
if (virDataTypesInitialize() < 0)
return NULL;
virCheckConnectGoto(conn, error);
virCheckNonNullArgGoto(uuid, error);
virCheckNonNullArgGoto(usageID, error);
if (!(ret = virObjectNew(virSecretClass)))
return NULL;
memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN);
ret->usageType = usageType;
if (VIR_STRDUP(ret->usageID, usageID) < 0)
goto error;
ret->conn = virObjectRef(conn);
return ret;
error:
virObjectUnref(ret);
return NULL;
}
/**
* virSecretDispose:
* @secret: the secret to release
*
* Unconditionally release all memory associated with a secret. The conn.lock
* mutex must be held prior to calling this, and will be released prior to this
* returning. The secret obj must not be used once this method returns.
*
* It will also unreference the associated connection object, which may also be
* released if its ref count hits zero.
*/
static void
virSecretDispose(void *obj)
{
virSecretPtr secret = obj;
Fix UUID handling in secrets/storage encryption APIs Convert all the secret/storage encryption APIs / wire format to handle UUIDs in raw format instead of non-canonical printable format. Guarentees data format correctness. * docs/schemas/storageencryption.rng: Make UUID mandatory for a secret and validate fully * docs/schemas/secret.rng: Fully validate UUID * include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add virSecretLookupByUUID and virSecretGetUUID. Make virSecretGetUUIDString follow normal API design pattern * python/generator.py: Skip generation of virSecretGetUUID, virSecretGetUUIDString and virSecretLookupByUUID * python/libvir.c, python/libvirt-python-api.xml: Manual impl of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID * qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/ Fix get_nonnull_secret/make_nonnull_secret to use unsigned char * qemud/remote_protocol.x: Fix remote_nonnull_secret to use a remote_uuid instead of remote_nonnull_string for UUID field. Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an remote_uuid value * qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h, qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h, qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate * src/datatypes.h, src/datatypes.c: Store UUID in raw format instead of printable. Change virGetSecret to use raw format UUID * src/driver.h: Rename virDrvSecretLookupByUUIDString to virDrvSecretLookupByUUID and use raw format UUID * src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID and re-implement virSecretLookupByUUIDString and virSecretGetUUIDString in terms of those * src/libvirt_public.syms: Add virSecretLookupByUUID and virSecretGetUUID * src/remote_internal.c: Rename remoteSecretLookupByUUIDString to remoteSecretLookupByUUID. Fix typo in args for remoteSecretDefineXML impl. Use raw UUID format for get_nonnull_secret and make_nonnull_secret * src/storage_encryption_conf.c, src/storage_encryption_conf.h: Storage UUID in raw format, and require it to be present in XML. Use UUID parser to validate. * secret_conf.h, secret_conf.c: Generate a UUID if none is provided. Storage UUID in raw format. * src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets in a filed with printable UUID, instead of base64 UUID. * src/virsh.c: Adjust for changed public API contract of virSecretGetUUIDString. * src/storage_Backend.c: DOn't undefine secret we just generated upon successful volume creation. Fix to handle raw UUIDs. Generate a non-clashing UUID * src/qemu_driver.c: Change to use lookupByUUID instead of lookupByUUIDString
2009-09-10 16:44:12 +00:00
char uuidstr[VIR_UUID_STRING_BUFLEN];
Fix UUID handling in secrets/storage encryption APIs Convert all the secret/storage encryption APIs / wire format to handle UUIDs in raw format instead of non-canonical printable format. Guarentees data format correctness. * docs/schemas/storageencryption.rng: Make UUID mandatory for a secret and validate fully * docs/schemas/secret.rng: Fully validate UUID * include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add virSecretLookupByUUID and virSecretGetUUID. Make virSecretGetUUIDString follow normal API design pattern * python/generator.py: Skip generation of virSecretGetUUID, virSecretGetUUIDString and virSecretLookupByUUID * python/libvir.c, python/libvirt-python-api.xml: Manual impl of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID * qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/ Fix get_nonnull_secret/make_nonnull_secret to use unsigned char * qemud/remote_protocol.x: Fix remote_nonnull_secret to use a remote_uuid instead of remote_nonnull_string for UUID field. Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an remote_uuid value * qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h, qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h, qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate * src/datatypes.h, src/datatypes.c: Store UUID in raw format instead of printable. Change virGetSecret to use raw format UUID * src/driver.h: Rename virDrvSecretLookupByUUIDString to virDrvSecretLookupByUUID and use raw format UUID * src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID and re-implement virSecretLookupByUUIDString and virSecretGetUUIDString in terms of those * src/libvirt_public.syms: Add virSecretLookupByUUID and virSecretGetUUID * src/remote_internal.c: Rename remoteSecretLookupByUUIDString to remoteSecretLookupByUUID. Fix typo in args for remoteSecretDefineXML impl. Use raw UUID format for get_nonnull_secret and make_nonnull_secret * src/storage_encryption_conf.c, src/storage_encryption_conf.h: Storage UUID in raw format, and require it to be present in XML. Use UUID parser to validate. * secret_conf.h, secret_conf.c: Generate a UUID if none is provided. Storage UUID in raw format. * src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets in a filed with printable UUID, instead of base64 UUID. * src/virsh.c: Adjust for changed public API contract of virSecretGetUUIDString. * src/storage_Backend.c: DOn't undefine secret we just generated upon successful volume creation. Fix to handle raw UUIDs. Generate a non-clashing UUID * src/qemu_driver.c: Change to use lookupByUUID instead of lookupByUUIDString
2009-09-10 16:44:12 +00:00
virUUIDFormat(secret->uuid, uuidstr);
VIR_DEBUG("release secret %p %s", secret, uuidstr);
VIR_FREE(secret->usageID);
virObjectUnref(secret->conn);
}
virStreamPtr
virGetStream(virConnectPtr conn)
{
virStreamPtr ret = NULL;
if (virDataTypesInitialize() < 0)
return NULL;
if (!(ret = virObjectNew(virStreamClass)))
return NULL;
ret->conn = virObjectRef(conn);
return ret;
}
static void
virStreamDispose(void *obj)
{
virStreamPtr st = obj;
VIR_DEBUG("release dev %p", st);
virObjectUnref(st->conn);
}
/**
* virGetNWFilter:
* @conn: the hypervisor connection
* @name: pointer to the network filter pool name
* @uuid: pointer to the uuid
*
* Lookup if the network filter is already registered for that connection,
* if yes return a new pointer to it, if no allocate a new structure,
* and register it in the table. In any case a corresponding call to
* virObjectUnref() is needed to not leak data.
*
* Returns a pointer to the network, or NULL in case of failure
*/
virNWFilterPtr
virGetNWFilter(virConnectPtr conn, const char *name,
const unsigned char *uuid)
{
virNWFilterPtr ret = NULL;
if (virDataTypesInitialize() < 0)
return NULL;
virCheckConnectGoto(conn, error);
virCheckNonNullArgGoto(name, error);
virCheckNonNullArgGoto(uuid, error);
if (!(ret = virObjectNew(virNWFilterClass)))
goto error;
if (VIR_STRDUP(ret->name, name) < 0)
goto error;
memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN);
ret->conn = virObjectRef(conn);
return ret;
error:
virObjectUnref(ret);
return NULL;
}
/**
* virNWFilterDispose:
* @nwfilter: the nwfilter to release
*
* Unconditionally release all memory associated with a nwfilter.
* The conn.lock mutex must be held prior to calling this, and will
* be released prior to this returning. The nwfilter obj must not
* be used once this method returns.
*
* It will also unreference the associated connection object,
* which may also be released if its ref count hits zero.
*/
static void
virNWFilterDispose(void *obj)
{
virNWFilterPtr nwfilter = obj;
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(nwfilter->uuid, uuidstr);
VIR_DEBUG("release nwfilter %p %s %s", nwfilter, nwfilter->name, uuidstr);
VIR_FREE(nwfilter->name);
virObjectUnref(nwfilter->conn);
}
virDomainSnapshotPtr
virGetDomainSnapshot(virDomainPtr domain, const char *name)
{
virDomainSnapshotPtr ret = NULL;
if (virDataTypesInitialize() < 0)
return NULL;
if (!VIR_IS_DOMAIN(domain)) {
maint: don't permit format strings without % Any time we have a string with no % passed through gettext, a translator can inject a % to cause a stack overread. When there is nothing to format, it's easier to ask for a string that cannot be used as a formatter, by using a trivial "%s" format instead. In the past, we have used --disable-nls to catch some of the offenders, but that doesn't get run very often, and many more uses have crept in. Syntax check to the rescue! The syntax check can catch uses such as virReportError(code, _("split " "string")); by using a sed script to fold context lines into one pattern space before checking for a string without %. This patch is just mechanical insertion of %s; there are probably several messages touched by this patch where we would be better off giving the user more information than a fixed string. * cfg.mk (sc_prohibit_diagnostic_without_format): New rule. * src/datatypes.c (virUnrefConnect, virGetDomain) (virUnrefDomain, virGetNetwork, virUnrefNetwork, virGetInterface) (virUnrefInterface, virGetStoragePool, virUnrefStoragePool) (virGetStorageVol, virUnrefStorageVol, virGetNodeDevice) (virGetSecret, virUnrefSecret, virGetNWFilter, virUnrefNWFilter) (virGetDomainSnapshot, virUnrefDomainSnapshot): Add %s wrapper. * src/lxc/lxc_driver.c (lxcDomainSetBlkioParameters) (lxcDomainGetBlkioParameters): Likewise. * src/conf/domain_conf.c (virSecurityDeviceLabelDefParseXML) (virDomainDiskDefParseXML, virDomainGraphicsDefParseXML): Likewise. * src/conf/network_conf.c (virNetworkDNSHostsDefParseXML) (virNetworkDefParseXML): Likewise. * src/conf/nwfilter_conf.c (virNWFilterIsValidChainName): Likewise. * src/conf/nwfilter_params.c (virNWFilterVarValueCreateSimple) (virNWFilterVarAccessParse): Likewise. * src/libvirt.c (virDomainSave, virDomainSaveFlags) (virDomainRestore, virDomainRestoreFlags) (virDomainSaveImageGetXMLDesc, virDomainSaveImageDefineXML) (virDomainCoreDump, virDomainGetXMLDesc) (virDomainMigrateVersion1, virDomainMigrateVersion2) (virDomainMigrateVersion3, virDomainMigrate, virDomainMigrate2) (virStreamSendAll, virStreamRecvAll) (virDomainSnapshotGetXMLDesc): Likewise. * src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel) (virNWFilterDHCPSnoopReq): Likewise. * src/openvz/openvz_driver.c (openvzUpdateDevice): Likewise. * src/openvz/openvz_util.c (openvzKBPerPages): Likewise. * src/qemu/qemu_cgroup.c (qemuSetupCgroup): Likewise. * src/qemu/qemu_command.c (qemuBuildHubDevStr, qemuBuildChrChardevStr) (qemuBuildCommandLine): Likewise. * src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise. * src/rpc/virnetsaslcontext.c (virNetSASLSessionGetIdentity): Likewise. * src/rpc/virnetsocket.c (virNetSocketNewConnectUNIX) (virNetSocketSendFD, virNetSocketRecvFD): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskBuildPool): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendFileSystemProbe) (virStorageBackendFileSystemBuild): Likewise. * src/storage/storage_backend_rbd.c (virStorageBackendRBDOpenRADOSConn): Likewise. * src/storage/storage_driver.c (storageVolumeResize): Likewise. * src/test/test_driver.c (testInterfaceChangeBegin) (testInterfaceChangeCommit, testInterfaceChangeRollback): Likewise. * src/vbox/vbox_tmpl.c (vboxListAllDomains): Likewise. * src/xenxs/xen_sxpr.c (xenFormatSxprDisk, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetUUID, xenFormatXMDisk) (xenFormatXM): Likewise.
2012-07-23 20:33:08 +00:00
virLibConnError(VIR_ERR_INVALID_DOMAIN, "%s", _("bad domain"));
return NULL;
}
virCheckNonNullArgReturn(name, NULL);
if (!(ret = virObjectNew(virDomainSnapshotClass)))
return NULL;
if (VIR_STRDUP(ret->name, name) < 0)
goto cleanup;
ret->domain = virObjectRef(domain);
return ret;
cleanup:
virObjectUnref(ret);
return NULL;
}
static void
virDomainSnapshotDispose(void *obj)
{
virDomainSnapshotPtr snapshot = obj;
VIR_DEBUG("release snapshot %p %s", snapshot, snapshot->name);
VIR_FREE(snapshot->name);
virObjectUnref(snapshot->domain);
}