[Libvir] handle PyTuple_New's malloc failure
Daniel P. Berrange
berrange at redhat.com
Thu Jan 17 15:52:00 UTC 2008
On Thu, Jan 17, 2008 at 04:41:49PM +0100, Jim Meyering wrote:
> python/libvir.c calls PyTuple_New, but doesn't handle the possibility
> of a NULL return value. Subsequent use of the result pointer in e.g.,
> PyTuple_SetItem, would dereference it.
>
> This fixes most of them, but leaves the ones in
> virConnectCredCallbackWrapper untouched. Fixing them
> properly is not as easy, and IMHO will require actual testing.
>
> In this patch, I combined each new test like this
>
> ((info = PyTuple_New(8)) == NULL)
>
> with the preceding "if (c_retval < 0)", since the bodies would be the same.
>
> Duplicating that 2-line body might look more readable,
> depending on which side of the bed you get up on...
> I can go either way.
I think it'd be nicer to keep the PyTuple_new bit separate as it is
now, because in some APIs there can be other code between the existing
c_retval < 0 check, and the point at which we create the Tuple.
eg, the libvirt_virDomainGetSchedulerParameters method in the
patch I'm attaching which implements a number of missing APIs
NB, this patch is not tested yet, so not intended to be applied
Might be useful to have a macro to combine the Py_INCREF and return
(Py_None) in one convenient blob. return VIR_PY_NONE();
> Subject: [PATCH] python/libvir.c: Handle PyTuple_New's malloc failure.
>
> ---
> python/libvir.c | 27 ++++++++++++---------------
> 1 files changed, 12 insertions(+), 15 deletions(-)
>
> diff --git a/python/libvir.c b/python/libvir.c
> index 3b41dc1..13b809f 100644
> --- a/python/libvir.c
> +++ b/python/libvir.c
> @@ -48,17 +48,16 @@ libvirt_virDomainBlockStats(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
>
> if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainBlockStats",
> &pyobj_domain,&path))
> - return(NULL);
> + return(NULL);
I curious as to why we ever return(NULL) here rather than Py_None. I'm
not sure of the python runtime / C binding contract - but returning an
actual NULL seems odd.
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
-------------- next part --------------
diff -r bb529870a27d python/generator.py
--- a/python/generator.py Tue Jan 15 12:38:10 2008 -0500
+++ b/python/generator.py Tue Jan 15 18:37:29 2008 -0500
@@ -229,6 +229,7 @@ py_types = {
'double': ('d', None, "double", "double"),
'unsigned int': ('i', None, "int", "int"),
'unsigned long': ('l', None, "long", "long"),
+ 'unsigned long long': ('l', None, "longlong", "long long"),
'unsigned char *': ('z', None, "charPtr", "char *"),
'char *': ('z', None, "charPtr", "char *"),
'const char *': ('z', None, "charPtrConst", "const char *"),
@@ -279,6 +280,11 @@ skip_impl = (
'virDomainBlockStats',
'virDomainInterfaceStats',
'virNodeGetCellsFreeMemory',
+ 'virDomainGetSchedulerType',
+ 'virDomainGetSchedulerParameters',
+ 'virDomainSetSchedulerParameters',
+ 'virDomainGetVcpus',
+ 'virDomainPinVcpu',
)
def skip_function(name):
@@ -918,6 +924,8 @@ def buildWrappers():
txt.write(" %s()\n" % func);
n = 0
for arg in args:
+ if name == "virDomainPinVcpu" and arg[0] == "maplen":
+ continue
if n != index:
classes.write(", %s" % arg[0])
n = n + 1
@@ -939,6 +947,8 @@ def buildWrappers():
classes.write("libvirtmod.%s(" % name)
n = 0
for arg in args:
+ if name == "virDomainPinVcpu" and arg[0] == "maplen":
+ continue
if n != 0:
classes.write(", ");
if n != index:
diff -r bb529870a27d python/libvir.c
--- a/python/libvir.c Tue Jan 15 12:38:10 2008 -0500
+++ b/python/libvir.c Tue Jan 15 18:37:29 2008 -0500
@@ -99,6 +99,321 @@ libvirt_virDomainInterfaceStats(PyObject
PyTuple_SetItem(info, 7, PyLong_FromLongLong(stats.tx_drop));
return(info);
}
+
+
+static PyObject *
+libvirt_virDomainGetSchedulerType(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args) {
+ virDomainPtr domain;
+ PyObject *pyobj_domain, *info;
+ char *c_retval;
+ int nparams;
+
+ if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetScedulerType",
+ &pyobj_domain))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ c_retval = virDomainGetSchedulerType(domain, &nparams);
+ if (c_retval == NULL) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ /* convert to a Python tupple of long objects */
+ info = PyTuple_New(2);
+ PyTuple_SetItem(info, 0, libvirt_constcharPtrWrap(c_retval));
+ PyTuple_SetItem(info, 1, PyInt_FromLong((long)nparams));
+ free(c_retval);
+ return(info);
+}
+
+static PyObject *
+libvirt_virDomainGetSchedulerParameters(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args) {
+ virDomainPtr domain;
+ PyObject *pyobj_domain, *info;
+ char *c_retval;
+ int nparams, i;
+ virSchedParameterPtr params;
+
+ if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetScedulerParameters",
+ &pyobj_domain))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ c_retval = virDomainGetSchedulerType(domain, &nparams);
+ if (c_retval == NULL) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+ free(c_retval);
+
+ if ((params = malloc(sizeof(*params)*nparams)) == NULL) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ if (virDomainGetSchedulerParameters(domain, params, &nparams) < 0) {
+ free(params);
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ /* convert to a Python tupple of long objects */
+ info = PyDict_New();
+ for (i = 0 ; i < nparams ; i++) {
+ PyObject *key, *val;
+
+ switch (params[i].type) {
+ case VIR_DOMAIN_SCHED_FIELD_INT:
+ val = PyInt_FromLong((long)params[i].value.i);
+ break;
+
+ case VIR_DOMAIN_SCHED_FIELD_UINT:
+ val = PyInt_FromLong((long)params[i].value.ui);
+ break;
+
+ case VIR_DOMAIN_SCHED_FIELD_LLONG:
+ val = PyLong_FromLongLong((long long)params[i].value.l);
+ break;
+
+ case VIR_DOMAIN_SCHED_FIELD_ULLONG:
+ val = PyLong_FromLongLong((long long)params[i].value.ul);
+ break;
+
+ case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
+ val = PyFloat_FromDouble((double)params[i].value.d);
+ break;
+
+ case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
+ val = PyBool_FromLong((long)params[i].value.b);
+ break;
+
+ default:
+ free(params);
+ Py_DECREF(info);
+ Py_INCREF(Py_None);
+ return (Py_None);
+ }
+
+ key = libvirt_constcharPtrWrap(params[i].field);
+ PyDict_SetItem(info, key, val);
+ }
+ free(params);
+ return(info);
+}
+
+static PyObject *
+libvirt_virDomainSetSchedulerParameters(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args) {
+ virDomainPtr domain;
+ PyObject *pyobj_domain, *info;
+ char *c_retval;
+ int nparams, i;
+ virSchedParameterPtr params;
+
+ if (!PyArg_ParseTuple(args, (char *)"OO:virDomainSetScedulerParameters",
+ &pyobj_domain, &info))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ c_retval = virDomainGetSchedulerType(domain, &nparams);
+ if (c_retval == NULL) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+ free(c_retval);
+
+ if ((params = malloc(sizeof(*params)*nparams)) == NULL) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ if (virDomainGetSchedulerParameters(domain, params, &nparams) < 0) {
+ free(params);
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ /* convert to a Python tupple of long objects */
+ for (i = 0 ; i < nparams ; i++) {
+ PyObject *key, *val;
+ key = libvirt_constcharPtrWrap(params[i].field);
+ val = PyDict_GetItem(info, key);
+ Py_DECREF(key);
+
+ if (val == NULL)
+ continue;
+
+ switch (params[i].type) {
+ case VIR_DOMAIN_SCHED_FIELD_INT:
+ params[i].value.i = (int)PyInt_AS_LONG(val);
+ break;
+
+ case VIR_DOMAIN_SCHED_FIELD_UINT:
+ params[i].value.ui = (unsigned int)PyInt_AS_LONG(val);
+ break;
+
+ case VIR_DOMAIN_SCHED_FIELD_LLONG:
+ params[i].value.l = (long long)PyLong_AsLongLong(val);
+ break;
+
+ case VIR_DOMAIN_SCHED_FIELD_ULLONG:
+ params[i].value.ul = (unsigned long long)PyLong_AsLongLong(val);
+ break;
+
+ case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
+ params[i].value.d = (double)PyFloat_AsDouble(val);
+ break;
+
+ case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
+ {
+ /* Hack - Python's definition of Py_True breaks strict
+ * aliasing rules, so can't directly compare :-(
+ */
+ PyObject *hacktrue = PyBool_FromLong(1);
+ params[i].value.b = hacktrue == val ? 1 : 0;
+ Py_DECREF(hacktrue);
+ }
+ break;
+
+ default:
+ free(params);
+ Py_INCREF(Py_None);
+ return (Py_None);
+ }
+ }
+
+ if (virDomainSetSchedulerParameters(domain, params, nparams) < 0) {
+ free(params);
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ free(params);
+ Py_INCREF(Py_None);
+ return(Py_None);
+}
+
+static PyObject *
+libvirt_virDomainGetVcpus(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args) {
+ virDomainPtr domain;
+ PyObject *pyobj_domain, *pyretval, *pycpuinfo, *pycpumap;
+ virNodeInfo nodeinfo;
+ virDomainInfo dominfo;
+ virVcpuInfoPtr cpuinfo;
+ unsigned char *cpumap;
+ int cpumaplen, i;
+
+ if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetVcpus",
+ &pyobj_domain))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ if (virNodeGetInfo(virDomainGetConnect(domain), &nodeinfo) != 0) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ if (virDomainGetInfo(domain, &dominfo) != 0) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ if ((cpuinfo = malloc(sizeof(*cpuinfo)*dominfo.nrVirtCpu)) == NULL) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+ cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
+ if ((cpumap = malloc(dominfo.nrVirtCpu * cpumaplen)) == NULL) {
+ free(cpuinfo);
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ if (virDomainGetVcpus(domain,
+ cpuinfo, dominfo.nrVirtCpu,
+ cpumap, cpumaplen) < 0) {
+ free(cpuinfo);
+ free(cpumap);
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ /* convert to a Python tupple of long objects */
+ pyretval = PyTuple_New(2);
+ pycpuinfo = PyList_New(dominfo.nrVirtCpu);
+ pycpumap = PyList_New(dominfo.nrVirtCpu);
+
+ for (i = 0 ; i < dominfo.nrVirtCpu ; i++) {
+ PyObject *info = PyTuple_New(4);
+ PyTuple_SetItem(info, 0, PyInt_FromLong((long)cpuinfo[i].number));
+ PyTuple_SetItem(info, 1, PyInt_FromLong((long)cpuinfo[i].state));
+ PyTuple_SetItem(info, 2, PyLong_FromLongLong((long long)cpuinfo[i].cpuTime));
+ PyTuple_SetItem(info, 3, PyInt_FromLong((long)cpuinfo[i].cpu));
+ PyList_SetItem(pycpuinfo, i, info);
+ }
+ for (i = 0 ; i < dominfo.nrVirtCpu ; i++) {
+ PyObject *info = PyTuple_New(VIR_NODEINFO_MAXCPUS(nodeinfo));
+ int j;
+ for (j = 0 ; j < VIR_NODEINFO_MAXCPUS(nodeinfo) ; j++) {
+ PyTuple_SetItem(info, j, PyBool_FromLong(VIR_CPU_USABLE(cpumap, cpumaplen, i, j)));
+ }
+ PyList_SetItem(pycpumap, i, info);
+ }
+ PyTuple_SetItem(pyretval, 0, pycpuinfo);
+ PyTuple_SetItem(pyretval, 1, pycpumap);
+
+ free(cpuinfo);
+ free(cpumap);
+
+ return(pyretval);
+}
+
+
+static PyObject *
+libvirt_virDomainPinVcpu(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args) {
+ virDomainPtr domain;
+ PyObject *pyobj_domain, *pycpumap, *truth;
+ virNodeInfo nodeinfo;
+ unsigned char *cpumap;
+ int cpumaplen, i;
+
+ if (!PyArg_ParseTuple(args, (char *)"OO:virDomainPinVcpu",
+ &pyobj_domain, &pycpumap))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ if (virNodeGetInfo(virDomainGetConnect(domain), &nodeinfo) != 0) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+
+ cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
+ if ((cpumap = malloc(cpumaplen)) == NULL) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+ memset(cpumap, 0, cpumaplen);
+
+ truth = PyBool_FromLong(1);
+ for (i = 0 ; i < VIR_NODEINFO_MAXCPUS(nodeinfo) ; i++) {
+ PyObject *flag = PyTuple_GetItem(pycpumap, i);
+ if (flag == truth)
+ VIR_USE_CPU(cpumap, i);
+ else
+ VIR_UNUSE_CPU(cpumap, i);
+ }
+ Py_DECREF(truth);
+
+ Py_INCREF(Py_None);
+ return(Py_None);
+}
+
+
/************************************************************************
* *
* Global error handler at the Python level *
@@ -917,6 +1232,11 @@ static PyMethodDef libvirtMethods[] = {
{(char *) "virDomainBlockStats", libvirt_virDomainBlockStats, METH_VARARGS, NULL},
{(char *) "virDomainInterfaceStats", libvirt_virDomainInterfaceStats, METH_VARARGS, NULL},
{(char *) "virNodeGetCellsFreeMemory", libvirt_virNodeGetCellsFreeMemory, METH_VARARGS, NULL},
+ {(char *) "virDomainGetSchedulerType", libvirt_virDomainGetSchedulerType, METH_VARARGS, NULL},
+ {(char *) "virDomainGetSchedulerParameters", libvirt_virDomainGetSchedulerParameters, METH_VARARGS, NULL},
+ {(char *) "virDomainSetSchedulerParameters", libvirt_virDomainSetSchedulerParameters, METH_VARARGS, NULL},
+ {(char *) "virDomainGetVcpus", libvirt_virDomainGetVcpus, METH_VARARGS, NULL},
+ {(char *) "virDomainPinVcpu", libvirt_virDomainPinVcpu, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
More information about the libvir-list
mailing list