Pre-Glib era which used malloc allowed the size of the client-side
buffers to be declared as 0, because malloc documents that it can either
return 0 or a unique pointer on 0 size allocations.
With glib this doesn't work anymore, because glib documents that for
such allocation requests NULL is always returned which results in an
error in our public API checks server-side.
This patch complements the fix in the RPC layer by explicitly erroring
out on the following combination of args used by our legacy APIs (their
moder equivalents don't suffer from this):
function(caller-allocated-array, size, ...) {
if (!caller-allocated-array && size > 0)
return error;
}
treating everything else as a valid input and potentially let that fail
on the server-side rather than client-side.
https://bugzilla.redhat.com/show_bug.cgi?id=
1772842
Signed-off-by: Erik Skultety <eskultet@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
} \
} while (0)
+/* This check is intended to be used with legacy APIs only which expect the
+ * caller to pre-allocate the target buffer.
+ * We want to allow callers pass NULL arrays if the size is declared as 0 and
+ * still succeed in calling the API.
+ */
+#define virCheckNonNullArrayArgGoto(argname, argsize, label) \
+ do { \
+ if (!argname && argsize > 0) { \
+ virReportInvalidNonNullArg(argname); \
+ goto label; \
+ } \
+ } while (0)
+
/* Count leading zeros in an unsigned int.
*
virCheckDomainReturn(domain, -1);
conn = domain->conn;
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, nameslen, error);
virCheckNonNegativeArgGoto(nameslen, error);
if (conn->driver->domainSnapshotListNames) {
virCheckDomainSnapshotReturn(snapshot, -1);
conn = snapshot->domain->conn;
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, nameslen, error);
virCheckNonNegativeArgGoto(nameslen, error);
if (conn->driver->domainSnapshotListChildrenNames) {
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(ids, error);
+ virCheckNonNullArrayArgGoto(ids, maxids, error);
virCheckNonNegativeArgGoto(maxids, error);
if (conn->driver->connectListDomains) {
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (conn->driver->connectListDefinedDomains) {
virCheckDomainReturn(domain, -1);
conn = domain->conn;
- virCheckNonNullArgGoto(cpumaps, error);
+ virCheckNonNullArrayArgGoto(cpumaps, ncpumaps, error);
virCheckPositiveArgGoto(ncpumaps, error);
virCheckPositiveArgGoto(maplen, error);
virCheckDomainReturn(dom, -1);
- if (maxerrors)
- virCheckNonNullArgGoto(errors, error);
- else
- virCheckNullArgGoto(errors, error);
+ virCheckNonNullArrayArgGoto(errors, maxerrors, error);
if (dom->conn->driver->domainGetDiskErrors) {
int ret = dom->conn->driver->domainGetDiskErrors(dom, errors,
virCheckDomainReturn(dom, -1);
virCheckReadOnlyGoto(dom->conn->flags, error);
- if (nmountpoints)
- virCheckNonNullArgGoto(mountpoints, error);
- else
- virCheckNullArgGoto(mountpoints, error);
+ virCheckNonNullArrayArgGoto(mountpoints, nmountpoints, error);
if (dom->conn->driver->domainFSFreeze) {
int ret = dom->conn->driver->domainFSFreeze(
virCheckDomainReturn(dom, -1);
virCheckReadOnlyGoto(dom->conn->flags, error);
- if (nmountpoints)
- virCheckNonNullArgGoto(mountpoints, error);
- else
- virCheckNullArgGoto(mountpoints, error);
+ virCheckNonNullArrayArgGoto(mountpoints, nmountpoints, error);
if (dom->conn->driver->domainFSThaw) {
int ret = dom->conn->driver->domainFSThaw(
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(freeMems, error);
+ virCheckNonNullArrayArgGoto(freeMems, maxCells, error);
virCheckPositiveArgGoto(maxCells, error);
virCheckNonNegativeArgGoto(startCell, error);
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (conn->interfaceDriver && conn->interfaceDriver->connectListInterfaces) {
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (conn->interfaceDriver && conn->interfaceDriver->connectListDefinedInterfaces) {
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (conn->networkDriver && conn->networkDriver->connectListNetworks) {
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (conn->networkDriver && conn->networkDriver->connectListDefinedNetworks) {
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (conn->nodeDeviceDriver && conn->nodeDeviceDriver->nodeListDevices) {
virResetLastError();
virCheckNodeDeviceReturn(dev, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (dev->conn->nodeDeviceDriver && dev->conn->nodeDeviceDriver->nodeDeviceListCaps) {
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (conn->nwfilterDriver && conn->nwfilterDriver->connectListNWFilters) {
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(uuids, error);
+ virCheckNonNullArrayArgGoto(uuids, maxuuids, error);
virCheckNonNegativeArgGoto(maxuuids, error);
if (conn->secretDriver != NULL && conn->secretDriver->connectListSecrets != NULL) {
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (conn->storageDriver && conn->storageDriver->connectListStoragePools) {
virResetLastError();
virCheckConnectReturn(conn, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (conn->storageDriver && conn->storageDriver->connectListDefinedStoragePools) {
virResetLastError();
virCheckStoragePoolReturn(pool, -1);
- virCheckNonNullArgGoto(names, error);
+ virCheckNonNullArrayArgGoto(names, maxnames, error);
virCheckNonNegativeArgGoto(maxnames, error);
if (pool->conn->storageDriver && pool->conn->storageDriver->storagePoolListVolumes) {