// TODO: remove need for this option
/* { dg-additional-options "-fanalyzer-checker=taint" } */

typedef __SIZE_TYPE__ size_t;
typedef const void *t_comptype;
typedef int (*t_compfunc)(t_comptype, t_comptype);

extern int *__errno_location(void)
  __attribute__((__nothrow__, __leaf__,__const__));
extern void free(void *__ptr)
  __attribute__((__nothrow__, __leaf__));
extern void *my_malloc1(const char *file, int line, size_t size);

int heapsort(void *vbase, size_t nmemb, size_t size, t_compfunc compar) {
  char tmp, *tmp1, *tmp2, *abase, *k, *p, *t;
  size_t cnt, i, j, l;

  if (nmemb <= 1)
    return (0);

  if (!size) {
    (*__errno_location()) = 22;
    return (-1);
  }

  k = my_malloc1(__FILE__, __LINE__, size);

  abase = (char *)vbase - size;

  for (l = nmemb / 2 + 1; --l;) {
    for (i = l; (j = i * 2) <= nmemb; i = j) {
      p = abase + j * size;
      if (j < nmemb && compar(p, p + size) < 0) {
        p += size;
        ++j;
      }
      t = abase + i * size;
      if (compar(p, t) <= 0)
        break;
      {
        cnt = size;
        do {
          tmp = *t;
          *t++ = *p;
          *p++ = tmp;
        } while (--cnt);
      };
    }
  };

  while (nmemb > 1) {
    {
      cnt = size;
      tmp1 = k;
      tmp2 = abase + nmemb * size;
      do {
        *tmp1++ = *tmp2++;
      } while (--cnt);
    };
    {
      cnt = size;
      tmp1 = abase + nmemb * size;
      tmp2 = abase + size;
      do {
        *tmp1++ = *tmp2++;
      } while (--cnt);
    };
    --nmemb;
    {
      for (i = 1; (j = i * 2) <= nmemb; i = j) {
        p = abase + j * size;
        if (j < nmemb && compar(p, p + size) < 0) {
          p += size;
          ++j;
        }
        t = abase + i * size;
        {
          cnt = size;
          tmp1 = t;
          tmp2 = p;
          do {
            *tmp1++ = *tmp2++;
          } while (--cnt);
        };
      }
      for (;;) {
        j = i;
        i = j / 2;
        p = abase + j * size;
        t = abase + i * size;
        if (j == 1 || compar(k, t) < 0) {
          {
            cnt = size;
            tmp1 = p;
            tmp2 = k;
            do {
              *tmp1++ = *tmp2++;
            } while (--cnt);
          };
          break;
        }
        {
          cnt = size;
          tmp1 = p;
          tmp2 = t;
          do {
            *tmp1++ = *tmp2++;
          } while (--cnt);
        };
      }
    };
  }
  free(k);
  return (0);
}
