summaryrefslogtreecommitdiffstats
path: root/src/basic/memory-util.h
blob: d03d52cd438827a023b29d83ed142ff8b701cedb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once

#include <inttypes.h>
#include <malloc.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>

#include "alloc-util.h"
#include "macro.h"
#include "memory-util-fundamental.h"

size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
#define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1))
#define PAGE_OFFSET(l) ((l) & (page_size() - 1))

/* Normal memcpy() requires src to be nonnull. We do nothing if n is 0. */
static inline void *memcpy_safe(void *dst, const void *src, size_t n) {
        if (n == 0)
                return dst;
        assert(src);
        return memcpy(dst, src, n);
}

/* Normal mempcpy() requires src to be nonnull. We do nothing if n is 0. */
static inline void *mempcpy_safe(void *dst, const void *src, size_t n) {
        if (n == 0)
                return dst;
        assert(src);
        return mempcpy(dst, src, n);
}

/* Normal memcmp() requires s1 and s2 to be nonnull. We do nothing if n is 0. */
static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
        if (n == 0)
                return 0;
        assert(s1);
        assert(s2);
        return memcmp(s1, s2, n);
}

/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */
static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) {
        return memcmp_safe(s1, s2, MIN(n1, n2))
            ?: CMP(n1, n2);
}

#define memzero(x,l)                                            \
        ({                                                      \
                size_t _l_ = (l);                               \
                if (_l_ > 0)                                    \
                        memset(x, 0, _l_);                      \
        })

#define zero(x) (memzero(&(x), sizeof(x)))

bool memeqbyte(uint8_t byte, const void *data, size_t length);

#define memeqzero(data, length) memeqbyte(0x00, data, length)

#define eqzero(x) memeqzero(x, sizeof(x))

static inline void *mempset(void *s, int c, size_t n) {
        memset(s, c, n);
        return (uint8_t*)s + n;
}

/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {

        if (needlelen <= 0)
                return (void*) haystack;

        if (haystacklen < needlelen)
                return NULL;

        assert(haystack);
        assert(needle);

        return memmem(haystack, haystacklen, needle, needlelen);
}

static inline void *mempmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
        const uint8_t *p;

        p = memmem_safe(haystack, haystacklen, needle, needlelen);
        if (!p)
                return NULL;

        return (uint8_t*) p + needlelen;
}

static inline void* erase_and_free(void *p) {
        size_t l;

        if (!p)
                return NULL;

        l = MALLOC_SIZEOF_SAFE(p);
        explicit_bzero_safe(p, l);
        return mfree(p);
}

static inline void erase_and_freep(void *p) {
        erase_and_free(*(void**) p);
}

/* Use with _cleanup_ to erase a single 'char' when leaving scope */
static inline void erase_char(char *p) {
        explicit_bzero_safe(p, sizeof(char));
}

/* An automatic _cleanup_-like logic for destroy arrays (i.e. pointers + size) when leaving scope */
struct ArrayCleanup {
        void **parray;
        size_t *pn;
        free_array_func_t pfunc;
};

static inline void array_cleanup(struct ArrayCleanup *c) {
        assert(c);

        assert(!c->parray == !c->pn);

        if (!c->parray)
                return;

        if (*c->parray) {
                assert(c->pfunc);
                c->pfunc(*c->parray, *c->pn);
                *c->parray = NULL;
        }

        *c->pn = 0;
}

#define CLEANUP_ARRAY(array, n, func)                                   \
        _cleanup_(array_cleanup) _unused_ struct ArrayCleanup CONCATENATE(_cleanup_array_, UNIQ) = { \
                .parray = (void**) &(array),                            \
                .pn = &(n),                                             \
                .pfunc = (free_array_func_t) ({                         \
                                void (*_f)(typeof(array[0]) *a, size_t b) = func; \
                                _f;                                     \
                        }),                                             \
        }