calloc.c raw

   1  #include <stdlib.h>
   2  #include <stdint.h>
   3  #include <string.h>
   4  #include <errno.h>
   5  #include "dynlink.h"
   6  
   7  static size_t mal0_clear(char *p, size_t n)
   8  {
   9  	const size_t pagesz = 4096; /* arbitrary */
  10  	if (n < pagesz) return n;
  11  #ifdef __GNUC__
  12  	typedef uint64_t __attribute__((__may_alias__)) T;
  13  #else
  14  	typedef unsigned char T;
  15  #endif
  16  	char *pp = p + n;
  17  	size_t i = (uintptr_t)pp & (pagesz - 1);
  18  	for (;;) {
  19  		pp = memset(pp - i, 0, i);
  20  		if (pp - p < pagesz) return pp - p;
  21  		for (i = pagesz; i; i -= 2*sizeof(T), pp -= 2*sizeof(T))
  22  		        if (((T *)pp)[-1] | ((T *)pp)[-2])
  23  				break;
  24  	}
  25  }
  26  
  27  static int allzerop(void *p)
  28  {
  29  	return 0;
  30  }
  31  weak_alias(allzerop, __malloc_allzerop);
  32  
  33  void *calloc(size_t m, size_t n)
  34  {
  35  	if (n && m > (size_t)-1/n) {
  36  		errno = ENOMEM;
  37  		return 0;
  38  	}
  39  	n *= m;
  40  	void *p = malloc(n);
  41  	if (!p || (!__malloc_replaced && __malloc_allzerop(p)))
  42  		return p;
  43  	n = mal0_clear(p, n);
  44  	return memset(p, 0, n);
  45  }
  46