[libvirt] [PATCH v4 09/13] Adapt to VIR_STRDUP and VIR_STRNDUP in src/util/*

Eric Blake eblake at redhat.com
Thu May 23 21:10:17 UTC 2013


On 05/20/2013 11:55 AM, Michal Privoznik wrote:
> ---
>  34 files changed, 357 insertions(+), 570 deletions(-)

I've got my work cut out for me!

> @@ -226,8 +228,11 @@ char *virBitmapFormat(virBitmapPtr bitmap)
>          return NULL;
>  
>      cur = virBitmapNextSetBit(bitmap, -1);
> -    if (cur < 0)
> -        return strdup("");
> +    if (cur < 0) {
> +        char *ret;
> +        ignore_value(VIR_STRDUP(ret, ""));
> +        return ret;

Hmm, I've seen this three-line pattern (declare temp var, strdup "" into
it, use the var) in several patches now.  I think it might help to have
a new function in virstring.h whose job in life is to return a malloc'd
copy of an empty string, as a one-liner, so that callers don't have to
mess with a temp var.  And notice that it's slightly more efficient to
just zero-initialize a malloc'd array of 1, instead of going through
strdup machinery, when we know the output will be an empty string.  Maybe:

/* Return a malloc'd empty string, or NULL after reporting OOM */
char *
virStringEmpty(void)
{
    char *ret;
  // assuming we fix VIR_ALLOC to report oom...
    ignore_value(VIR_ALLOC(ret));
    return ret;
}

then THIS code could use the shorter:

if (cur < 0)
    return virStringEmpty();

But if you decide to go that route, it's probably worth a separate
cleanup pass, so this commit is not delayed.

> +++ b/src/util/vircgroup.c
> @@ -116,19 +116,13 @@ static int virCgroupCopyMounts(virCgroupPtr group,
>          if (!parent->controllers[i].mountPoint)
>              continue;
>  
> -        group->controllers[i].mountPoint =
> -            strdup(parent->controllers[i].mountPoint);
> -
> -        if (!group->controllers[i].mountPoint)
> +        if (VIR_STRDUP(group->controllers[i].mountPoint,
> +                       parent->controllers[i].mountPoint) < 0)
>              return -ENOMEM;

double-oom, since this function was previously silent and callers
already expected to do their own error reporting.  This whole file has
an unusual paradigm compared to most source files, it may be best to
split this file into a separate patch (so that you aren't holding up the
rest of src/util/*) and either use VIR_STRDUP_QUIET or start to tackle
the bigger issue of tracing through callers to behave better when leaf
functions report errors.

>  
> -        if (parent->controllers[i].linkPoint) {
> -            group->controllers[i].linkPoint =
> -                strdup(parent->controllers[i].linkPoint);
> -
> -            if (!group->controllers[i].linkPoint)
> -                return -ENOMEM;
> -        }
> +        if (VIR_STRDUP(group->controllers[i].linkPoint,
> +                       parent->controllers[i].linkPoint) < 0)
> +            return -ENOMEM;

again, double-oom

> @@ -177,7 +171,7 @@ static int virCgroupDetectMounts(virCgroupPtr group)
>                      struct stat sb;
>                      char *tmp2;
>  
> -                    if (!(group->controllers[i].mountPoint = strdup(entry.mnt_dir)))
> +                    if (VIR_STRDUP(group->controllers[i].mountPoint, entry.mnt_dir) < 0)
>                          goto no_memory;

no_memory label is redudant; VIR_STRDUP guarantees that 'errno ==
ENOMEM' if it returns -1, as do VIR_ALLOC and virAsprintf.  (Hmm, maybe
we should enhance './configure --enable-test-oom' to specifically test
that; although it may be a surprising amount of work to get that to
happen).  This is a silent->noisy change, and again an instance where
the cgroup callers are doing their own error reporting; and the
no_memory label is a bit awkward because it is not doing its own OOM
reporting.  Just deleting the no_memory label, and using 'goto error'
will make the code a bit less confusing.  And it reiterates my thought
that src/util/vircgroup.c is enough of an oddball to warrant being split
into its own patch.

So with that, I'll quit pointing out silent->noisy changes in this file,
and just point out other problems.

> @@ -1027,8 +1021,8 @@ static int virCgroupAddTaskStrController(virCgroupPtr group,
>      int rc = 0;
>      char *endp;
>  
> -    if (!(str = strdup(pidstr)))
> -        return -1;
> +    if (VIR_STRDUP(str, pidstr) < 0)
> +        return -ENOMEM;

Yikes! Are we mixing -1 and -errno in the same function?  That's an
independent bug, and probably better to isolate that fix into an
independent commit.

> +++ b/src/util/vircommand.c
> @@ -946,9 +946,8 @@ virCommandSetPidFile(virCommandPtr cmd, const char *pidfile)
>          return;
>  
>      VIR_FREE(cmd->pidfile);
> -    if (!(cmd->pidfile = strdup(pidfile))) {
> +    if (VIR_STRDUP(cmd->pidfile, pidfile) < 0)
>          cmd->has_error = ENOMEM;

double-oom.  More precisely, we DON'T want to report oom until
virCommandRun sees cmd->has_error==ENOMEM, so that callers have the
option of building up a virCommand but ditching it halfway through if
they encounter some other (more important) error.

Thus, this should use VIR_STRDUP_QUIET.

> @@ -1049,7 +1048,7 @@ virCommandSetSELinuxLabel(virCommandPtr cmd,
>  
>  #if defined(WITH_SECDRIVER_SELINUX)
>      VIR_FREE(cmd->seLinuxLabel);
> -    if (label && !(cmd->seLinuxLabel = strdup(label)))
> +    if (VIR_STRDUP(cmd->seLinuxLabel, label) < 0)
>          cmd->has_error = ENOMEM;

VIR_STRDUP_QUIET

>  #endif
>      return;
> @@ -1074,7 +1073,7 @@ virCommandSetAppArmorProfile(virCommandPtr cmd,
>  
>  #if defined(WITH_SECDRIVER_APPARMOR)
>      VIR_FREE(cmd->appArmorProfile);
> -    if (profile && !(cmd->appArmorProfile = strdup(profile)))
> +    if (VIR_STRDUP(cmd->appArmorProfile, profile) < 0)
>          cmd->has_error = ENOMEM;

QUIET

>  #endif
>      return;
> @@ -1205,7 +1204,7 @@ virCommandAddEnvString(virCommandPtr cmd, const char *str)
>      if (!cmd || cmd->has_error)
>          return;
>  
> -    if (!(env = strdup(str))) {
> +    if (VIR_STRDUP(env, str) < 0) {
>          cmd->has_error = ENOMEM;

QUIET

>          return;
>      }
> @@ -1309,7 +1308,7 @@ virCommandAddArg(virCommandPtr cmd, const char *val)
>      if (!cmd || cmd->has_error)
>          return;
>  
> -    if (!(arg = strdup(val))) {
> +    if (VIR_STRDUP(arg, val) < 0) {
>          cmd->has_error = ENOMEM;

QUIET

>          return;
>      }
> @@ -1350,11 +1349,11 @@ virCommandAddArgBuffer(virCommandPtr cmd, virBufferPtr buf)
>      }
>  
>      cmd->args[cmd->nargs] = virBufferContentAndReset(buf);
> -    if (!cmd->args[cmd->nargs])
> -        cmd->args[cmd->nargs] = strdup("");
>      if (!cmd->args[cmd->nargs]) {
> -        cmd->has_error = ENOMEM;
> -        return;
> +        if (VIR_STRDUP(cmd->args[cmd->nargs], "") < 0) {
> +            cmd->has_error = ENOMEM;

QUIET

> +            return;
> +        }
>      }
>      cmd->nargs++;
>  }
> @@ -1440,8 +1439,9 @@ virCommandAddArgSet(virCommandPtr cmd, const char *const*vals)
>  
>      narg = 0;
>      while (vals[narg] != NULL) {
> -        char *arg = strdup(vals[narg++]);
> -        if (!arg) {
> +        char *arg;
> +
> +        if (VIR_STRDUP(arg, vals[narg++]) < 0) {
>              cmd->has_error = ENOMEM;

QUIET

>              return;
>          }
> @@ -1481,8 +1481,7 @@ virCommandAddArgList(virCommandPtr cmd, ...)
>          char *arg = va_arg(list, char *);
>          if (!arg)
>              break;
> -        arg = strdup(arg);
> -        if (!arg) {
> +        if (VIR_STRDUP(arg, arg) < 0) {
>              cmd->has_error = ENOMEM;

QUIET

>              va_end(list);
>              return;
> @@ -1511,8 +1510,7 @@ virCommandSetWorkingDirectory(virCommandPtr cmd, const char *pwd)
>          cmd->has_error = -1;
>          VIR_DEBUG("cannot set directory twice");
>      } else {
> -        cmd->pwd = strdup(pwd);
> -        if (!cmd->pwd)
> +        if (VIR_STRDUP(cmd->pwd, pwd) < 0)
>              cmd->has_error = ENOMEM;

QUIET

>      }
>  }
> @@ -1539,8 +1537,7 @@ virCommandSetInputBuffer(virCommandPtr cmd, const char *inbuf)
>          return;
>      }
>  
> -    cmd->inbuf = strdup(inbuf);
> -    if (!cmd->inbuf)
> +    if (VIR_STRDUP(cmd->inbuf, inbuf) < 0)
>          cmd->has_error = ENOMEM;

QUIET

> +++ b/src/util/virebtables.c
> @@ -187,10 +189,10 @@ ebtRulesNew(const char *table,
>      if (VIR_ALLOC(rules) < 0)
>          return NULL;
>  
> -    if (!(rules->table = strdup(table)))
> +    if (VIR_STRDUP(rules->table, table) < 0)
>          goto error;

silent->noisy, caller was already doing its own reporting based on errno
value.  Probably a good change, but it means we probably ought to
eventually touch up qemuStateInitialize to not duplicate error handling.

> @@ -237,36 +239,36 @@ ebtablesAddRemoveRule(ebtRules *rules, int action, const char *arg, ...)
>  
>  #if HAVE_FIREWALLD
>      if (firewall_cmd_path) {
> -        if (!(argv[n++] = strdup(firewall_cmd_path)))
> +        if (VIR_STRDUP(argv[n++], firewall_cmd_path) < 0)
>              goto error;

Not for this patch, but why are we building up argv manually instead of
using virCommand?

> +++ b/src/util/virerror.c
> @@ -164,7 +164,8 @@ virErrorGenericFailure(virErrorPtr err)
>      err->code = VIR_ERR_INTERNAL_ERROR;
>      err->domain = VIR_FROM_NONE;
>      err->level = VIR_ERR_ERROR;
> -    err->message = strdup(_("An error occurred, but the cause is unknown"));
> +    ignore_value(VIR_STRDUP_QUIET(err->message,
> +                                  _("An error occurred, but the cause is unknown")));
>  }

This use of QUIET is correct.

>  
>  
> @@ -184,13 +185,13 @@ virCopyError(virErrorPtr from,
>      to->code = from->code;
>      to->domain = from->domain;
>      to->level = from->level;
> -    if (from->message && !(to->message = strdup(from->message)))
> +    if (from->message && VIR_STRDUP_QUIET(to->message, from->message) < 0)

Simplify:

if (VIR_STRDUP_QUIET(to->message, from->message) < 0)

>          ret = -1;
> -    if (from->str1 && !(to->str1 = strdup(from->str1)))
> +    if (from->str1 && VIR_STRDUP_QUIET(to->str1, from->str1) < 0)
>          ret = -1;
> -    if (from->str2 && !(to->str2 = strdup(from->str2)))
> +    if (from->str2 && VIR_STRDUP_QUIET(to->str2, from->str2) < 0)
>          ret = -1;
> -    if (from->str3 && !(to->str3 = strdup(from->str3)))
> +    if (from->str3 && VIR_STRDUP_QUIET(to->str3, from->str3) < 0)

and so on.

> @@ -687,11 +688,11 @@ virRaiseErrorFull(const char *filename ATTRIBUTE_UNUSED,
>      to->message = str;
>      to->level = level;
>      if (str1 != NULL)
> -        to->str1 = strdup(str1);
> +        ignore_value(VIR_STRDUP_QUIET(to->str1, str1));

Can lose the surrounding if.

>      if (str2 != NULL)
> -        to->str2 = strdup(str2);
> +        ignore_value(VIR_STRDUP_QUIET(to->str2, str2));
>      if (str3 != NULL)
> -        to->str3 = strdup(str3);
> +        ignore_value(VIR_STRDUP_QUIET(to->str3, str3));

and so on.

> +++ b/src/util/virfile.c
> @@ -1059,7 +1059,7 @@ virFileFindMountPoint(const char *type)
>  
>      while (getmntent_r(f, &mb, mntbuf, sizeof(mntbuf))) {
>          if (STREQ(mb.mnt_type, type)) {
> -            ret = strdup(mb.mnt_dir);
> +            ignore_value(VIR_STRDUP(ret, mb.mnt_dir));
>              goto cleanup;

silent->noisy.  This function has a bug: it says it returns NULL with
errno set, but then it does:

    if (!ret)
        errno = ENOENT;

cleanup:
    endmntent(f);

    return ret;

and endmntent is allowed to clobber errno.  But I think the intent is
that we DO want this function to be silent (meaning this should use
QUIET), because some callers ignore certain errors.

> @@ -1299,11 +1299,8 @@ virFileResolveLinkHelper(const char *linkpath,
>          if (lstat(linkpath, &st) < 0)
>              return -1;
>  
> -        if (!S_ISLNK(st.st_mode)) {
> -            if (!(*resultpath = strdup(linkpath)))
> -                return -1;
> -            return 0;
> -        }
> +        if (!S_ISLNK(st.st_mode))
> +            return VIR_STRDUP(*resultpath, linkpath) < 0 ? -1 : 0 ;

silent->noisy; looks like it needs to use _QUIET because callers ignore
some errors.

> @@ -1377,10 +1374,10 @@ virFindFileInPath(const char *file)
>       * copy of that path, after validating that it is executable
>       */
>      if (IS_ABSOLUTE_FILE_NAME(file)) {
> +        char *ret = NULL;
>          if (virFileIsExecutable(file))
> -            return strdup(file);
> -        else
> -            return NULL;
> +            ignore_value(VIR_STRDUP(ret, file));

silent->noisy; I think some callers ignore failure, so QUIET may be better.

> @@ -1395,7 +1392,7 @@ virFindFileInPath(const char *file)
>      /* copy PATH env so we can tweak it */
>      path = getenv("PATH");
>  
> -    if (path == NULL || (path = strdup(path)) == NULL)
> +    if (VIR_STRDUP(path, path) <= 0)
>          return NULL;

and again.

> @@ -2047,8 +2044,10 @@ virFileMakePathWithMode(const char *path,
>      int ret = -1;
>      char *tmp;
>  
> -    if ((tmp = strdup(path)) == NULL)
> +    if (VIR_STRDUP(tmp, path) < 0) {
> +        errno = ENOMEM;
>          goto cleanup;
> +    }

silent->noisy, but this one is probably okay.

> @@ -2257,7 +2256,7 @@ virFileAbsPath(const char *path, char **abspath)
>      char *buf;
>  
>      if (path[0] == '/') {
> -        if (!(*abspath = strdup(path)))
> +        if (VIR_STRDUP(*abspath, path) < 0)
>              return -1;

silent->noisy, but probably okay

> +++ b/src/util/viriptables.c
> @@ -119,10 +119,10 @@ iptRulesNew(const char *table,
>      if (VIR_ALLOC(rules) < 0)
>          return NULL;
>  
> -    if (!(rules->table = strdup(table)))
> +    if (VIR_STRDUP(rules->table, table) < 0)
>          goto error;

silent->noisy; probably okay, but we should adjust callers at some point

> +++ b/src/util/virjson.c
> @@ -107,7 +107,7 @@ virJSONValuePtr virJSONValueNewString(const char *data)
>          return NULL;
>  
>      val->type = VIR_JSON_TYPE_STRING;
> -    if (!(val->data.string = strdup(data))) {
> +    if (VIR_STRDUP(val->data.string, data) < 0) {
>          VIR_FREE(val);
>          return NULL;

silent->noisy, but probably a good change.  True for most of this file.

> +++ b/src/util/virlog.c
> @@ -557,8 +557,7 @@ virLogDefineFilter(const char *match,
>          }
>      }
>  
> -    mdup = strdup(match);
> -    if (mdup == NULL) {
> +    if (VIR_STRDUP_QUIET(mdup, match) < 0) {
>          i = -1;
>          goto cleanup;
>      }
> @@ -574,6 +573,8 @@ virLogDefineFilter(const char *match,
>      virLogNbFilters++;
>  cleanup:
>      virLogUnlock();
> +    if (i < 0)
> +        virReportOOMError();

silent->noisy; there are other failure paths where we are still silent,
but it's probably better to be noisy.  I think you did this construct so
that teh VIR_ALLOC_N also converts from silent->noisy, where a future
OOM cleanup path would then switch to VIR_STRDUP instead of
VIR_STRDUP_QUIET, although I'd rather live with double-oom now than
forget to drop QUIET later.

> @@ -664,13 +665,9 @@ virLogDefineOutput(virLogOutputFunc f,
>      if (f == NULL)
>          return -1;
>  
> -    if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) {
> -        if (name == NULL)
> -            return -1;
> -        ndup = strdup(name);
> -        if (ndup == NULL)
> -            return -1;
> -    }
> +    if ((dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) &&
> +        VIR_STRDUP(ndup, name) <= 0)
> +        return -1;

Hmm; this means you are silent->noisy on OOM, but still silent if name
was NULL.  It might be better to be consistently noisy, even if that
means you can't use the <= as planned.

> @@ -1047,8 +1044,7 @@ virLogAddOutputToSyslog(virLogPriority priority,
>       * ident needs to be kept around on Solaris
>       */
>      VIR_FREE(current_ident);
> -    current_ident = strdup(ident);
> -    if (current_ident == NULL)
> +    if (VIR_STRDUP(current_ident, ident) < 0)
>          return -1;

silent->noisy, but probably good

> @@ -1329,8 +1325,7 @@ virLogParseOutputs(const char *outputs)
>              if (str == cur)
>                  goto cleanup;
>  #if HAVE_SYSLOG_H
> -            name = strndup(str, cur - str);
> -            if (name == NULL)
> +            if (VIR_STRNDUP(name, str, cur - str) < 0)
>                  goto cleanup;

silent->noisy, but rest of function isn't consistently noisy

> +++ b/src/util/virnetdevmacvlan.c
> @@ -764,14 +765,14 @@ virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname,
>      if (virtPortProfile && virNetlinkEventServiceIsRunning(NETLINK_ROUTE)) {
>          if (VIR_ALLOC(calld) < 0)
>              goto memory_error;
> -        if ((calld->cr_ifname = strdup(ifname)) == NULL)
> -            goto memory_error;
> +        if (VIR_STRDUP(calld->cr_ifname, ifname) < 0)
> +            goto error;
>          if (VIR_ALLOC(calld->virtPortProfile) < 0)
>              goto memory_error;
>          memcpy(calld->virtPortProfile, virtPortProfile, sizeof(*virtPortProfile));
>          virMacAddrSet(&calld->macaddress, macaddress);
> -        if ((calld->linkdev = strdup(linkdev)) == NULL)
> -            goto  memory_error;
> +        if (VIR_STRDUP(calld->linkdev, linkdev) < 0)
> +            goto  error;

As long as you are touching this, kill the double space.

> +++ b/src/util/virsexpr.c
> @@ -119,16 +119,10 @@ sexpr_string(const char *str, ssize_t len)
>      if (ret == NULL)
>          return ret;
>      ret->kind = SEXPR_VALUE;
> -    if (len > 0) {
> -        ret->u.value = strndup(str, len);
> -    } else {
> -        ret->u.value = strdup(str);
> -    }
>  
> -    if (ret->u.value == NULL) {
> +    if ((len > 0 && VIR_STRNDUP(ret->u.value, str, len) < 0) ||
> +        (len <= 0 && VIR_STRDUP(ret->u.value, str) < 0))

if (VIR_STRNDUP(ret->u.value, str, len > 0 ? len : strlen(str)) < 0)

> +++ b/src/util/virstring.c
> @@ -109,6 +109,7 @@ char **virStringSplit(const char *string,
>  
>  no_memory:
>      virReportOOMError();
> +error:
>      for (i = 0 ; i < ntokens ; i++)

Might have a merge conflict with the semicolon cleanup.

> +++ b/src/util/virsysinfo.c
> @@ -145,32 +145,26 @@ virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret)
>      cur = strchr(cur, ':') + 1;
>      eol = strchr(cur, '\n');
>      virSkipSpaces(&cur);
> -    if (eol &&
> -       ((ret->system_family = strndup(cur, eol - cur)) == NULL))
> -         goto no_memory;
> +    if (eol && VIR_STRNDUP(ret->system_family, cur, eol - cur) < 0)
> +        return -1;
>  

silent->noisy, but probably a good change.

> @@ -186,43 +180,37 @@ virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
>          cur = strchr(base, ':') + 1;
>  
>          if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) {
> -            goto no_memory;
> +            return -1;
>          }
>          processor = &ret->processor[ret->nprocessor - 1];
>  
>          virSkipSpaces(&cur);
> -        if (eol &&
> -            ((processor->processor_socket_destination = strndup
> -                                     (cur, eol - cur)) == NULL))
> -            goto no_memory;
> +        if (eol && VIR_STRNDUP(processor->processor_socket_destination,
> +                               cur, eol - cur) < 0)
> +            return -1;

silent->noisy, but probably good

> @@ -271,32 +259,26 @@ virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret)
> @@ -314,10 +296,8 @@ virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
>      eol = strchr(base, '\n');
>      cur = strchr(base, ':') + 1;
>      virSkipSpaces(&cur);
> -    if (eol &&
> -        ((processor_type = strndup(cur, eol - cur))
> -         == NULL))
> -        goto no_memory;
> +    if (eol && VIR_STRNDUP(processor_type, cur, eol - cur) < 0)
> +        goto error;

and more silent->noisy; probably the whole file is impacted.

>      base = cur;
>  
>      while ((tmp_base = strstr(base, "processor")) != NULL) {
> @@ -326,19 +306,20 @@ virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
>          cur = strchr(base, ':') + 1;
>  
>          if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) {
> -            goto no_memory;
> +            virReportOOMError();
> +            goto error;
>          }

Another silent->noisy, and here you were dealing with VIR_EXPAND_N.

> @@ -463,7 +440,8 @@ virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
>              goto cleanup;
>          }
>          processor = &ret->processor[ret->nprocessor - 1];
> -        processor->processor_manufacturer = strdup(manufacturer);
> +        if (VIR_STRDUP(processor->processor_manufacturer, manufacturer) < 0)
> +            goto cleanup;

silent->noisy, but probably good.

Everything else looked good.  There were a few problems to fix up before
pushing, and maybe it's worth resubmitting vircgroup cleanups (or doing
an explicit followup), but I can live with giving:

ACK

I agree that we want this series in before we freeze.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 621 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20130523/67973afd/attachment-0001.sig>


More information about the libvir-list mailing list