1 #include <stdlib.h>
2 #include <stdint.h>
3 #include <string.h>
4 #include <errno.h>
5 #include "dynlink.h"
6 
mal0_clear(char *p, size_t n)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 
allzerop(void *p)27 static int allzerop(void *p)
28 {
29 	return 0;
30 }
31 weak_alias(allzerop, __malloc_allzerop);
32 
__libc_calloc(size_t m, size_t n)33 void *__libc_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 = __libc_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 
47 #ifdef HOOK_ENABLE
hook_calloc(size_t m, size_t n)48 void *hook_calloc(size_t m, size_t n)
49 {
50 	if (n && m > (size_t)-1/n) {
51 		errno = ENOMEM;
52 		return 0;
53 	}
54 	n *= m;
55 	void *p = __libc_malloc(n);
56 	if (!p || (!__malloc_replaced && __malloc_allzerop(p)))
57 		return p;
58 	n = mal0_clear(p, n);
59 	return memset(p, 0, n);
60 }
61 #endif
62