1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 #pragma once
3
4 #include <inttypes.h>
5 #include <malloc.h>
6 #include <stdbool.h>
7 #include <string.h>
8 #include <sys/types.h>
9
10 #include "alloc-util.h"
11 #include "macro.h"
12
13 size_t page_size(void) _pure_;
14 #define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
15 #define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1))
16 #define PAGE_OFFSET(l) ((l) & (page_size() - 1))
17
18 /* Normal memcpy() requires src to be nonnull. We do nothing if n is 0. */
memcpy_safe(void * dst,const void * src,size_t n)19 static inline void *memcpy_safe(void *dst, const void *src, size_t n) {
20 if (n == 0)
21 return dst;
22 assert(src);
23 return memcpy(dst, src, n);
24 }
25
26 /* Normal mempcpy() requires src to be nonnull. We do nothing if n is 0. */
mempcpy_safe(void * dst,const void * src,size_t n)27 static inline void *mempcpy_safe(void *dst, const void *src, size_t n) {
28 if (n == 0)
29 return dst;
30 assert(src);
31 return mempcpy(dst, src, n);
32 }
33
34 /* Normal memcmp() requires s1 and s2 to be nonnull. We do nothing if n is 0. */
memcmp_safe(const void * s1,const void * s2,size_t n)35 static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
36 if (n == 0)
37 return 0;
38 assert(s1);
39 assert(s2);
40 return memcmp(s1, s2, n);
41 }
42
43 /* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */
memcmp_nn(const void * s1,size_t n1,const void * s2,size_t n2)44 static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) {
45 return memcmp_safe(s1, s2, MIN(n1, n2))
46 ?: CMP(n1, n2);
47 }
48
49 #define memzero(x,l) \
50 ({ \
51 size_t _l_ = (l); \
52 if (_l_ > 0) \
53 memset(x, 0, _l_); \
54 })
55
56 #define zero(x) (memzero(&(x), sizeof(x)))
57
58 bool memeqbyte(uint8_t byte, const void *data, size_t length);
59
60 #define memeqzero(data, length) memeqbyte(0x00, data, length)
61
62 #define eqzero(x) memeqzero(x, sizeof(x))
63
mempset(void * s,int c,size_t n)64 static inline void *mempset(void *s, int c, size_t n) {
65 memset(s, c, n);
66 return (uint8_t*)s + n;
67 }
68
69 /* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
memmem_safe(const void * haystack,size_t haystacklen,const void * needle,size_t needlelen)70 static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
71
72 if (needlelen <= 0)
73 return (void*) haystack;
74
75 if (haystacklen < needlelen)
76 return NULL;
77
78 assert(haystack);
79 assert(needle);
80
81 return memmem(haystack, haystacklen, needle, needlelen);
82 }
83
mempmem_safe(const void * haystack,size_t haystacklen,const void * needle,size_t needlelen)84 static inline void *mempmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
85 const uint8_t *p;
86
87 p = memmem_safe(haystack, haystacklen, needle, needlelen);
88 if (!p)
89 return NULL;
90
91 return (uint8_t*) p + needlelen;
92 }
93
94 #if HAVE_EXPLICIT_BZERO
explicit_bzero_safe(void * p,size_t l)95 static inline void* explicit_bzero_safe(void *p, size_t l) {
96 if (l > 0)
97 explicit_bzero(p, l);
98
99 return p;
100 }
101 #else
102 void *explicit_bzero_safe(void *p, size_t l);
103 #endif
104
erase_and_free(void * p)105 static inline void* erase_and_free(void *p) {
106 size_t l;
107
108 if (!p)
109 return NULL;
110
111 l = MALLOC_SIZEOF_SAFE(p);
112 explicit_bzero_safe(p, l);
113 return mfree(p);
114 }
115
erase_and_freep(void * p)116 static inline void erase_and_freep(void *p) {
117 erase_and_free(*(void**) p);
118 }
119
120 /* Use with _cleanup_ to erase a single 'char' when leaving scope */
erase_char(char * p)121 static inline void erase_char(char *p) {
122 explicit_bzero_safe(p, sizeof(char));
123 }
124