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