John,

On Fri, Sep 14, 2018 at 5:04 PM, John Ferlan <jferlan@redhat.com> wrote:


On 09/11/2018 08:59 AM, Fabiano Fidêncio wrote:
> There are still a few places using virConfGetValue(), checking for the
> specific type of the pointers and so on. However, those places are not
> going to be converted as:
> - Using virConfGetValue*() would trigger virReportError() in the current
> code, which would cause, at least, some misleading messages for whoever
> has to debug this code path;
> - Expanding virConfValue*() to support strings as other types (for
> instance, as boolean or long) does not seem to be neither the safest nor
> the preferential path to take.
>
> Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
> ---
>  src/xenconfig/xen_common.c | 163 +++++++++++++++++--------------------
>  1 file changed, 75 insertions(+), 88 deletions(-)
>

/me thinks much of the above probably should have gone under the ---
indicating your knowledge of more places, but the decision to not change
them for the stated reasons. That commit message doesn't necessarily
describe the subsequent changes...

Perhaps a generic commit messages such as:

Change to using virConfGetValueString rather than open coding for
instances in which error messages are expected to be generated.

Okay!
 

> diff --git a/src/xenconfig/xen_common.c b/src/xenconfig/xen_common.c
> index fdca9845aa..c31ebfb270 100644
> --- a/src/xenconfig/xen_common.c
> +++ b/src/xenconfig/xen_common.c
> @@ -145,31 +145,19 @@ xenConfigCopyStringInternal(virConfPtr conf,
>                              char **value,
>                              int allowMissing)
>  {
> -    virConfValuePtr val;
> +    int rc;

>      *value = NULL;
> -    if (!(val = virConfGetValue(conf, name))) {
> -        if (allowMissing)
> -            return 0;
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("config value %s was missing"), name);
> -        return -1;
> -    }
> +    rc = virConfGetValueString(conf, name, value);

I believe this should be:

    if ((rc = virConfGetValueString(conf, name, value)) < 0)
        return -1;

otherwise, we could get to the allowMissing w/ rc == -1 and return 0
even though previously for a VIR_STRDUP failure we'd return -1. We'd
also overwrite the no memory error from VIR_STRDUP failure.

Fixed locally, thanks!
 


> +    if (rc == 1 && *value)
> +        return 0;

> -    if (val->type != VIR_CONF_STRING) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("config value %s was not a string"), name);
> -        return -1;
> -    }
> -    if (!val->str) {
> -        if (allowMissing)
> -            return 0;
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("config value %s was missing"), name);
> -        return -1;
> -    }
> +    if (allowMissing)
> +        return 0;

> -    return VIR_STRDUP(*value, val->str);
> +    virReportError(VIR_ERR_INTERNAL_ERROR,
> +                   _("config value %s was missing"), name);
> +    return -1;
>  }


> @@ -193,7 +181,7 @@ xenConfigCopyStringOpt(virConfPtr conf, const char *name, char **value)
>  static int
>  xenConfigGetUUID(virConfPtr conf, const char *name, unsigned char *uuid)
>  {
> -    virConfValuePtr val;
> +    char *string = NULL;

>      if (!uuid || !name || !conf) {
>          virReportError(VIR_ERR_INVALID_ARG, "%s",
> @@ -201,7 +189,7 @@ xenConfigGetUUID(virConfPtr conf, const char *name, unsigned char *uuid)
>          return -1;
>      }

> -    if (!(val = virConfGetValue(conf, name))) {
> +    if (virConfGetValueString(conf, name, &string) < 0) {

This is not the same check - < 0 is returned on errors (!STRING and
VIR_STRDUP failure).

I think you should use:

    rc = virConfGetValueString(conf, name, &string);

and then continue from there with the rc and/or string checks.

Fixed locally, thanks!
 

>          if (virUUIDGenerate(uuid) < 0) {
>              virReportError(VIR_ERR_INTERNAL_ERROR,
>                             "%s", _("Failed to generate UUID"));
> @@ -211,24 +199,20 @@ xenConfigGetUUID(virConfPtr conf, const char *name, unsigned char *uuid)
>          }
>      }

> -    if (val->type != VIR_CONF_STRING) {
> -        virReportError(VIR_ERR_CONF_SYNTAX,
> -                       _("config value %s not a string"), name);
> -        return -1;
> -    }
> -
> -    if (!val->str) {
> +    if (!string) {

I think this would be if virConfGetValueString returns 1, but !string
because VIR_STRDUP(*value, NULL) would return NULL in *value.

Fixed locally, thanks!
 

>          virReportError(VIR_ERR_CONF_SYNTAX,
>                         _("%s can't be empty"), name);
>          return -1;
>      }

> -    if (virUUIDParse(val->str, uuid) < 0) {
> +    if (virUUIDParse(string, uuid) < 0) {
>          virReportError(VIR_ERR_CONF_SYNTAX,
> -                       _("%s not parseable"), val->str);
> +                       _("%s not parseable"), string);
> +        VIR_FREE(string);
>          return -1;
>      }

> +    VIR_FREE(string);
>      return 0;
>  }

> @@ -242,23 +226,16 @@ xenConfigGetString(virConfPtr conf,
>                     const char **value,
>                     const char *def)
>  {
> -    virConfValuePtr val;
> +    char *string = NULL;

> -    *value = NULL;
> -    if (!(val = virConfGetValue(conf, name))) {
> +    if (virConfGetValueString(conf, name, &string) < 0) {

more of the same here as from previous < 0 is error, while ret == 0
would be this case

Fixed locally, thanks!
 

>          *value = def;
> -        return 0;
> -    }
> -
> -    if (val->type != VIR_CONF_STRING) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("config value %s was malformed"), name);
>          return -1;
>      }
> -    if (!val->str)
> +    if (!string)

and if rc == 1 and !string

>          *value = def;
>      else
> -        *value = val->str;
> +        *value = string;

And the problem here is that @string would be leaked since it's a
VIR_STRDUP of val->str, the @*def is a const char of something.


Here we can just memcpy() the string content and VIR_FREE() the string. Would you agree with this approach or do you have something else in mind?

 
>      return 0;
>  }

> @@ -469,27 +446,30 @@ xenParsePCI(char *entry)
>  static int
>  xenParsePCIList(virConfPtr conf, virDomainDefPtr def)
>  {
> -    virConfValuePtr list = virConfGetValue(conf, "pci");
> +    char **pcis = NULL, **entries;
> +    int ret = -1;

> -    if (!list || list->type != VIR_CONF_LIST)
> +    if (virConfGetValueStringList(conf, "pci", false, &pcis) <= 0)

Again, not the same checks... Not sure this particular one can be used.
The < 0 is an error path...

I understand your point that we're not doing the same check, but I do believe that the "<= 0" check here is okay if we want to keep the same behaviour.

The main issue I see here is that if the list->type is from the wrong type, virConfGetValueStringList() would end up returning -1 (considering it goes to the default branch, for instance) and the old code would return 0 for that case.

So, < 0 is an error path, but I'm not sure how we can differentiate between the errors we want to return 0 and the ones we want to return -1.
 

I'm imagining many of the rest are similar.  Probably should have split
things up into single patches for each method (as painful as it is) so
that it's easier to review and easier to pick and choose what doesn't
work and what does.

BTW: I would do all the virConfGetValueString's first... Then tackle the
virConfGetValueStringList's - since it doesn't cause one to context
switch "too much" between two different API's.


Sure, I'll submit a new version soon (after having your feedback in the question above).
 

John

>          return 0;

> -    for (list = list->list; list; list = list->next) {
> +    for (entries = pcis; *entries; entries++) {
> +        char *entry = *entries;
>          virDomainHostdevDefPtr hostdev;

> -        if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
> -            continue;
> -
> -        if (!(hostdev = xenParsePCI(list->str)))
> -            return -1;
> +        if (!(hostdev = xenParsePCI(entry)))
> +            goto cleanup;

>          if (VIR_APPEND_ELEMENT(def->hostdevs, def->nhostdevs, hostdev) < 0) {
>              virDomainHostdevDefFree(hostdev);
> -            return -1;
> +            goto cleanup;
>          }
>      }

> -    return 0;
> +    ret = 0;
> +
> + cleanup:
> +    virStringListFree(pcis);
> +    return ret;
>  }


> @@ -603,10 +583,11 @@ xenParseCPUFeatures(virConfPtr conf,
>  static int
>  xenParseVfb(virConfPtr conf, virDomainDefPtr def)
>  {
> +    int ret = -1;
>      int val;
> +    char **vfbs = NULL;
>      char *listenAddr = NULL;
>      int hvm = def->os.type == VIR_DOMAIN_OSTYPE_HVM;
> -    virConfValuePtr list;
>      virDomainGraphicsDefPtr graphics = NULL;

>      if (hvm) {
> @@ -662,17 +643,24 @@ xenParseVfb(virConfPtr conf, virDomainDefPtr def)
>      }

>      if (!hvm && def->graphics == NULL) { /* New PV guests use this format */
> -        list = virConfGetValue(conf, "vfb");
> -        if (list && list->type == VIR_CONF_LIST &&
> -            list->list && list->list->type == VIR_CONF_STRING &&
> -            list->list->str) {
> +        char **entries;
> +        int rc;
> +
> +        rc = virConfGetValueStringList(conf, "vfb", false, &vfbs);
> +        if (rc <= 0) {
> +            ret = 0;
> +            goto cleanup;
> +        }
> +
> +        for (entries = vfbs; *entries; entries++) {
>              char vfb[MAX_VFB];
>              char *key = vfb;
> +            char *entry = *entries;

> -            if (virStrcpyStatic(vfb, list->list->str) < 0) {
> +            if (virStrcpyStatic(vfb, entry) < 0) {
>                  virReportError(VIR_ERR_INTERNAL_ERROR,
>                                 _("VFB %s too big for destination"),
> -                               list->list->str);
> +                               entry);
>                  goto cleanup;
>              }

> @@ -745,21 +733,23 @@ xenParseVfb(virConfPtr conf, virDomainDefPtr def)
>          }
>      }

> -    return 0;
> +    ret = 0;

>   cleanup:
>      virDomainGraphicsDefFree(graphics);
>      VIR_FREE(listenAddr);
> -    return -1;
> +    virStringListFree(vfbs);
> +    return ret;
>  }


>  static int
>  xenParseCharDev(virConfPtr conf, virDomainDefPtr def, const char *nativeFormat)
>  {
> +    char **serials = NULL;
>      const char *str;
> -    virConfValuePtr value = NULL;
>      virDomainChrDefPtr chr = NULL;
> +    int ret = -1;

>      if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
>          if (xenConfigGetString(conf, "parallel", &str, NULL) < 0)
> @@ -779,8 +769,8 @@ xenParseCharDev(virConfPtr conf, virDomainDefPtr def, const char *nativeFormat)
>          }

>          /* Try to get the list of values to support multiple serial ports */
> -        value = virConfGetValue(conf, "serial");
> -        if (value && value->type == VIR_CONF_LIST) {
> +        if (virConfGetValueStringList(conf, "serial", false, &serials) == 1) {
> +            char **entries;
>              int portnum = -1;

>              if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
> @@ -789,18 +779,12 @@ xenParseCharDev(virConfPtr conf, virDomainDefPtr def, const char *nativeFormat)
>                  goto cleanup;
>              }

> -            value = value->list;
> -            while (value) {
> -                char *port = NULL;
> +            for (entries = serials; *entries; entries++) {
> +                char *port = *entries;

> -                if ((value->type != VIR_CONF_STRING) || (value->str == NULL))
> -                    goto cleanup;
> -                port = value->str;
>                  portnum++;
> -                if (STREQ(port, "none")) {
> -                    value = value->next;
> +                if (STREQ(port, "none"))
>                      continue;
> -                }

>                  if (!(chr = xenParseSxprChar(port, NULL)))
>                      goto cleanup;
> @@ -808,8 +792,6 @@ xenParseCharDev(virConfPtr conf, virDomainDefPtr def, const char *nativeFormat)
>                  chr->target.port = portnum;
>                  if (VIR_APPEND_ELEMENT(def->serials, def->nserials, chr) < 0)
>                      goto cleanup;
> -
> -                value = value->next;
>              }
>          } else {
>              /* If domain is not using multiple serial ports we parse data old way */
> @@ -825,6 +807,7 @@ xenParseCharDev(virConfPtr conf, virDomainDefPtr def, const char *nativeFormat)
>                  chr->target.port = 0;
>                  def->serials[0] = chr;
>                  def->nserials++;
> +                chr = NULL;
>              }
>          }
>      } else {
> @@ -838,11 +821,12 @@ xenParseCharDev(virConfPtr conf, virDomainDefPtr def, const char *nativeFormat)
>          def->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
>      }

> -    return 0;
> +    ret = 0;

>   cleanup:
>      virDomainChrDefFree(chr);
> -    return -1;
> +    virStringListFree(serials);
> +    return ret;
>  }


> @@ -1031,29 +1015,32 @@ xenParseVif(char *entry, const char *vif_typename)
>  static int
>  xenParseVifList(virConfPtr conf, virDomainDefPtr def, const char *vif_typename)
>  {
> -    virConfValuePtr list = virConfGetValue(conf, "vif");
> +    char **vifs = NULL, **entries;
> +    int ret = -1;

> -    if (!list || list->type != VIR_CONF_LIST)
> +    if (virConfGetValueStringList(conf, "vif", false, &vifs) <= 0)
>          return 0;

> -    for (list = list->list; list; list = list->next) {
> +    for (entries = vifs; *entries; entries++) {
>          virDomainNetDefPtr net = NULL;
> +        char *entry = *entries;
>          int rc;

> -        if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
> -            continue;
> -
> -        if (!(net = xenParseVif(list->str, vif_typename)))
> -            return -1;
> +        if (!(net = xenParseVif(entry, vif_typename)))
> +            goto cleanup;

>          rc = VIR_APPEND_ELEMENT(def->nets, def->nnets, net);
>          if (rc < 0) {
>              virDomainNetDefFree(net);
> -            return -1;
> +            goto cleanup;
>          }
>      }

> -    return 0;
> +    ret = 0;
> +
> + cleanup:
> +    virStringListFree(vifs);
> +    return ret;
>  }


>