On Fri, May 25, 2012 at 05:35:20PM -0600, Eric Blake wrote:
> +# define virReportInvalidNullArg(argname)
\
> + virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \
> + VIR_FROM_THIS, \
> + VIR_ERR_INVALID_ARG, \
> + VIR_ERR_ERROR, \
> + __FUNCTION__, \
> + #argname, \
> + NULL, \
> + 0, 0, \
> + _("%s in %s must be NULL"), \
> + #argname, __FUNCTION__)
Still feels a little redundant to report __FUNCTION__ in both the
location and in the message, but at least the message is sane and by
funnelling all clients through this one point you can change the message
in the future with a lot less effort. I can live with it.
Although when we send the error message onto virLogMessage(), the
function name will be prepended to the error string, if the application
has installed a custom handler for virErrorPtr they may well only be
printing out the error message. Thus I want to make sure that the error
message is "self contained" and not rely on people printing out other
data fields from the virErrorPtr.
> +# define virReportInvalidArg(argname, fmt, ...)
\
> + virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \
> + VIR_FROM_THIS, \
> + VIR_ERR_INVALID_ARG, \
> + VIR_ERR_ERROR, \
> + __FUNCTION__, \
> + #argname, \
> + NULL, \
> + 0, 0, \
> + (fmt), __VA_ARGS__)
This requires a fmt argument and subsequent arguments, probably a good
thing since you aren't using it for a canned message.
Is the idea that down the road you will add a syntax check that forbids
raw use of VIR_ERR_INVALID_ARG, and must instead use
virReportInvalidArg() or a better error category?
Yes, I think we should deny direct use of VIR_ERR_INVALID_ARG once
this conversion is complete.
> return retval;
\
> } \
> } while (0)
>
> +# define virCheckNonNullArgReturn(argname, retval) \
> + do { \
> + if (argname == NULL) { \
> + virReportInvalidNullArg(#argname); \
Hmm. This stringizes 'argname', but then virReportInvalidNullArg() also
stringizes its argument. Does that mean we are actually generating
messages with literal quotes injected due to the double stringize?
func: "arg" in func must not be NULL
That double stringizing is a mistake.
> @@ -813,7 +790,7 @@ virUnrefStorageVol(virStorageVolPtr vol) {
> int refs;
>
> if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) {
> - virLibConnError(VIR_ERR_INVALID_ARG,
> + virLibConnError(VIR_ERR_INVALID_STORAGE_VOL,
> _("bad storage volume or no connection"));
> return -1;
> }
I'm wondering if a future patch should factor out these checks for valid
object into a one-liner as well, such as virCheckStorageVolReturn(vol,
NULL). But doesn't need to be done for the current patch.
Yes, shortening this is definitely my intention.
> +++ b/src/libvirt.c
> @@ -746,12 +725,6 @@ virRegisterDriver(virDriverPtr driver)
> return -1;
> }
>
> - if (driver->no < 0) {
> - virLibConnError(VIR_ERR_INVALID_ARG,
> - _("Tried to register an internal Xen driver"));
> - return -1;
> - }
> -
Why'd we drop this one? But it looks okay.
Originally the Xen sub-drivers uses the same virDriverPtr struct,
but now they have a dedicated xenUnifiedDriver struct instead.
> @@ -5018,8 +4917,18 @@ virDomainMigratePeer2Peer (virDomainPtr
domain,
> return -1;
> }
>
> - if (!tempuri->server || STRPREFIX(tempuri->server,
"localhost")) {
> - virLibConnError(VIR_ERR_INVALID_ARG, __FUNCTION__);
> + if (!tempuri->server) {
> + virReportInvalidArg(tempuri,
> + _("server field in tempuri in %s must not be
NULL"),
> + __FUNCTION__);
Wrong message. tempuri is something we constructed ourselves
(virURIParse), and not something the user passed in. Rather, we should
say something like:
virReportInvalidArg(dconnuri,
_("Unable to parse server from dconnuri in %s"), __FUNCTION);
Ah, ok I missed that
> @@ -8638,9 +8532,12 @@ virDomainPinVcpu(virDomainPtr domain,
unsigned int vcpu,
> goto error;
> }
>
> - if ((vcpu > 32000) || (cpumap == NULL) || (maplen < 1)) {
> - virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
> - goto error;
> + virCheckNonNullArgGoto(cpumap, error);
> + virCheckPositiveArgGoto(maplen, error);
> +
> + if ((unsigned short) vcpu != vcpu) {
Not strictly equivalent to '(vcpu > 32000)', but does a similar job (but
only because 'vcpu' is unsigned; if it were signed, then you get into
subtleties where it might not work).
I did this change, because several other places related to vCPUs were
already doing this cast+compare, so it is better to be consistent about
the precise point at which we raise errors.
> @@ -11590,13 +11413,12 @@
virStoragePoolLookupByUUIDString(virConnectPtr conn,
> virDispatchError(NULL);
> return NULL;
> }
> - if (uuidstr == NULL) {
> - virLibConnError(VIR_ERR_INVALID_ARG, __FUNCTION__);
> - goto error;
> - }
> + virCheckNonNullArgGoto(uuidstr, error);
>
> if (virUUIDParse(uuidstr, uuid) < 0) {
> - virLibConnError(VIR_ERR_INVALID_ARG, __FUNCTION__);
> + virReportInvalidArg(uuidstr,
> + _("uuidstr in %s must be a valid UUID"),
> + __FUNCTION__);
> goto error;
The virUUIDParse() failure case is another frequent one that might be
worth factoring into a one-liner.
Yes, definitely.
It is also my intent to simplify the checks for the read-only flag.
> @@ -14381,15 +14143,15 @@ virSecretGetUUID(virSecretPtr secret,
unsigned char *uuid)
> virDispatchError(NULL);
> return -1;
> }
> - if (uuid == NULL) {
> - virLibSecretError(VIR_ERR_INVALID_ARG, __FUNCTION__);
> - virDispatchError(secret->conn);
> - return -1;
> - }
> + virCheckNonNullArgGoto(uuid, error);
>
> memcpy(uuid, &secret->uuid[0], VIR_UUID_BUFLEN);
>
> return 0;
> +
> +error:
> + virDispatchError(NULL);
Oops. Why the change from secret->conn to NULL?
Bugtastic.
> @@ -16716,8 +16428,12 @@
virConnectDomainEventRegisterAny(virConnectPtr conn,
> virDispatchError(conn);
> return -1;
> }
> - if (eventID < 0 || eventID >= VIR_DOMAIN_EVENT_ID_LAST || cb == NULL) {
> - virLibConnError(VIR_ERR_INVALID_ARG, __FUNCTION__);
> + virCheckNonNullArgGoto(cb, error);
> + virCheckNonNegativeArgGoto(eventID, error);
> + if (eventID >= VIR_DOMAIN_EVENT_ID_LAST) {
> + virReportInvalidArg(eventID,
> + _("eventID in %s must be less than %d"),
> + __FUNCTION__, VIR_DOMAIN_EVENT_ID_LAST);
No change in functionality by this hunk (so if you fix it, make it a
separate patch), but I think we have an independent bug here. Suppose
that I have a client compiled against 0.9.13 headers, but running
against the 0.9.12 libvirt.so, and it is talking to an 0.9.13 server.
This check prevents me from registering for an event new to 0.9.13, even
though both client and server know about it, all because the
intermediary RPC call is rejecting values. I think the check for
eventID too large has to be pushed down into the drivers, not here in
libvirt.c.
Yes that is probably right.
> @@ -17131,20 +16843,23 @@ virDomainSnapshotCreateXML(virDomainPtr domain,
>
> if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT) &&
> !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
> - virLibDomainError(VIR_ERR_INVALID_ARG,
> - _("use of current flag requires redefine
flag"));
> + virReportInvalidArg(flags,
> + _("use of current flag in %s requires redefine
flag"),
Elsewhere, you used quoting to make it obvious which flags were being
talked about, as in: "use of 'current' flag in %s requires
'redefine' flag".
Good point.
> @@ -18724,13 +18406,19 @@ int virDomainGetCPUStats(virDomainPtr domain,
> * ncpus must be non-zero unless params == NULL
> * nparams * ncpus must not overflow (RPC may restrict it even more)
> */
> - if (start_cpu < -1 ||
> - (start_cpu == -1 && ncpus != 1) ||
> - ((params == NULL) != (nparams == 0)) ||
> - (ncpus == 0 && params != NULL)) {
> - virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
> + if (start_cpu < -1 && ncpus != -1) {
> + virReportInvalidArg(start_cpu,
> + _("start_cpu in %s must be -1 or greater if ncpus
is not -1"),
> + __FUNCTION__);
Huh? You botched that conversion. Consider:
start_cpu == -2, ncpus == 0 # old code rejected, new code lets through
start_cpu == -1, ncpus == -1 # old code rejected, new code lets through
I think you want:
if (start_cpu == -1) {
if (ncpus != 1) {
virReportInvalidArg(ncpus,
_("ncpus in %s must be 1 when start_cpu is -1"), __FUNCTION);
goto error;
}
} else {
virCheckNonNegativeArgGoto(start_cpu, error);
}
Hmm, don't know what I was thinking there !
> +++ b/src/nodeinfo.c
> @@ -451,8 +451,9 @@ int linuxNodeGetCPUStats(FILE *procstat,
> }
>
> if ((*nparams) != LINUX_NB_CPU_STATS) {
> - nodeReportError(VIR_ERR_INVALID_ARG,
> - "%s", _("Invalid parameter count"));
> + virReportInvalidArg(*nparams,
> + _("nparams in %s must be equal to %d"),
> + __FUNCTION__, LINUX_NB_CPU_STATS);
Faithful conversion, but latent bug that we should fix. I remember
changing lots of similar situations to specifically allow *nparams to be
smaller (truncate the result, good for new server talking to old library
that only cares about the first parameter) or larger (ignore the extras,
good for old server talking to new library that knows about more
results, but can still behave when those results are not present).
Yes, it is a little odd, but before changing this, I'd have to examine
the code in more detail
Daniel
--
|:
http://berrange.com -o-
http://www.flickr.com/photos/dberrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|:
http://entangle-photo.org -o-
http://live.gnome.org/gtk-vnc :|