potentially incorrect conversion of pointer to unsigned long

Vincent Lefevre vincent at vinc17.org
Sat Jun 22 07:42:36 UTC 2019

I've noticed after the latest changes (but the issue is older),
in init.c:

static void mutt_set_default (struct option_t *p)
  switch (p->type & DT_MASK)
    case DT_STR:
    case DT_PATH:
      if (!p->init && *((char **) p->data))
        p->init = (unsigned long) safe_strdup (* ((char **) p->data));
    case DT_ADDR:
      if (!p->init && *((ADDRESS **) p->data))
        char tmp[HUGE_STRING];
        *tmp = '\0';
        rfc822_write_address (tmp, sizeof (tmp), *((ADDRESS **) p->data), 0);
        p->init = (unsigned long) safe_strdup (tmp);
    case DT_RX:
      REGEXP *pp = (REGEXP *) p->data;
      if (!p->init && pp->pattern)
        p->init = (unsigned long) safe_strdup (pp->pattern);

where safe_strdup returns a char *. Thus one has conversions of a
pointer (char *) to unsigned long. This is implementation-defined
and can even be undefined behavior if "the result cannot be
represented in the integer type", in particular if unsigned long
is smaller than pointers (e.g. with the LLP64 data model, like
under MS Windows64).

There is also the same kind of issue with the MuttVars initializer
in init.h.

Now, I think that if (uintptr_t) -1 <= (unsigned long) -1, the
Mutt code should be OK (I assume that the result of a conversion
between a pointer and an integer does not depend on the integer
type, but I know that not all people agree with me).

IMHO, the best solution for safety would be to use a union (I think
that this would require the use of C99 designators for the MuttVars
initialization). Otherwise check (uintptr_t) -1 <= (unsigned long) -1
in configure.

Vincent Lefèvre <vincent at vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)

More information about the Mutt-dev mailing list