fix struct layout mismatch in sound ioctl time32 fallback conversion
[musl] / src / malloc / calloc.c
index 436c0b0..bf6bddc 100644 (file)
@@ -1,7 +1,34 @@
 #include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
 #include <errno.h>
+#include "dynlink.h"
 
-void *__malloc0(size_t);
+static size_t mal0_clear(char *p, size_t n)
+{
+       const size_t pagesz = 4096; /* arbitrary */
+       if (n < pagesz) return n;
+#ifdef __GNUC__
+       typedef uint64_t __attribute__((__may_alias__)) T;
+#else
+       typedef unsigned char T;
+#endif
+       char *pp = p + n;
+       size_t i = (uintptr_t)pp & (pagesz - 1);
+       for (;;) {
+               pp = memset(pp - i, 0, i);
+               if (pp - p < pagesz) return pp - p;
+               for (i = pagesz; i; i -= 2*sizeof(T), pp -= 2*sizeof(T))
+                       if (((T *)pp)[-1] | ((T *)pp)[-2])
+                               break;
+       }
+}
+
+static int allzerop(void *p)
+{
+       return 0;
+}
+weak_alias(allzerop, __malloc_allzerop);
 
 void *calloc(size_t m, size_t n)
 {
@@ -9,5 +36,10 @@ void *calloc(size_t m, size_t n)
                errno = ENOMEM;
                return 0;
        }
-       return __malloc0(n * m);
+       n *= m;
+       void *p = malloc(n);
+       if (!p || (!__malloc_replaced && __malloc_allzerop(p)))
+               return p;
+       n = mal0_clear(p, n);
+       return memset(p, 0, n);
 }