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