File: memory-util-fundamental.h

package info (click to toggle)
stubble 3-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 836 kB
  • sloc: ansic: 6,119; python: 599; makefile: 40
file content (137 lines) | stat: -rw-r--r-- 5,296 bytes parent folder | download | duplicates (2)
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
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once

#include <stddef.h>

#include "efi-string.h"

#include "assert-fundamental.h"
#include "cleanup-fundamental.h"
#include "macro-fundamental.h"

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

static inline void *explicit_bzero_safe(void *p, size_t l) {
        if (p && l > 0) {
                memset(p, 0, l);
                __asm__ __volatile__("" : : "r"(p) : "memory");
        }
        return p;
}

struct VarEraser {
        /* NB: This is a pointer to memory to erase in case of CLEANUP_ERASE(). Pointer to pointer to memory
         * to erase in case of CLEANUP_ERASE_PTR() */
        void *p;
        size_t size;
};

static inline void erase_var(struct VarEraser *e) {
        explicit_bzero_safe(e->p, e->size);
}

/* Mark var to be erased when leaving scope. */
#define CLEANUP_ERASE(var)                                              \
        _cleanup_(erase_var) _unused_ struct VarEraser CONCATENATE(_eraser_, UNIQ) = { \
                .p = &(var),                                            \
                .size = sizeof(var),                                    \
        }

static inline void erase_varp(struct VarEraser *e) {

        /* Very similar to erase_var(), but assumes `p` is a pointer to a pointer whose memory shall be destructed. */
        if (!e->p)
                return;

        explicit_bzero_safe(*(void**) e->p, e->size);
}

/* Mark pointer so that memory pointed to is erased when leaving scope. Note: this takes a pointer to the
 * specified pointer, instead of just a copy of it. This is to allow callers to invalidate the pointer after
 * use, if they like, disabling our automatic erasure (for example because they succeeded with whatever they
 * wanted to do and now intend to return the allocated buffer to their caller without it being erased). */
#define CLEANUP_ERASE_PTR(ptr, sz)                                      \
        _cleanup_(erase_varp) _unused_ struct VarEraser CONCATENATE(_eraser_, UNIQ) = { \
                .p = (ptr),                                             \
                .size = (sz),                                           \
        }

static inline size_t ALIGN_TO(size_t l, size_t ali) {
        assert(ISPOWEROF2(ali));

        if (l > SIZE_MAX - (ali - 1))
                return SIZE_MAX; /* indicate overflow */

        return ((l + (ali - 1)) & ~(ali - 1));
}

static inline uint64_t ALIGN_TO_U64(uint64_t l, uint64_t ali) {
        assert(ISPOWEROF2(ali));

        if (l > UINT64_MAX - (ali - 1))
                return UINT64_MAX; /* indicate overflow */

        return ((l + (ali - 1)) & ~(ali - 1));
}

static inline size_t ALIGN_DOWN(size_t l, size_t ali) {
        assert(ISPOWEROF2(ali));

        return l & ~(ali - 1);
}

static inline uint64_t ALIGN_DOWN_U64(uint64_t l, uint64_t ali) {
        assert(ISPOWEROF2(ali));

        return l & ~(ali - 1);
}

static inline size_t ALIGN_OFFSET(size_t l, size_t ali) {
        assert(ISPOWEROF2(ali));

        return l & (ali - 1);
}

static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) {
        assert(ISPOWEROF2(ali));

        return l & (ali - 1);
}

#define ALIGN2(l) ALIGN_TO(l, 2)
#define ALIGN4(l) ALIGN_TO(l, 4)
#define ALIGN8(l) ALIGN_TO(l, 8)
#define ALIGN2_PTR(p) ((void*) ALIGN2((uintptr_t) p))
#define ALIGN4_PTR(p) ((void*) ALIGN4((uintptr_t) p))
#define ALIGN8_PTR(p) ((void*) ALIGN8((uintptr_t) p))
#define ALIGN(l)  ALIGN_TO(l, sizeof(void*))
#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p)))

/* Checks if the specified pointer is aligned as appropriate for the specific type */
#define IS_ALIGNED16(p) (((uintptr_t) p) % alignof(uint16_t) == 0)
#define IS_ALIGNED32(p) (((uintptr_t) p) % alignof(uint32_t) == 0)
#define IS_ALIGNED64(p) (((uintptr_t) p) % alignof(uint64_t) == 0)

/* Same as ALIGN_TO but callable in constant contexts. */
#define CONST_ALIGN_TO(l, ali)                                         \
        __builtin_choose_expr(                                         \
                __builtin_constant_p(l) &&                             \
                __builtin_constant_p(ali) &&                           \
                CONST_ISPOWEROF2(ali) &&                               \
                (l <= SIZE_MAX - (ali - 1)),      /* overflow? */      \
                ((l) + (ali) - 1) & ~((ali) - 1),                      \
                VOID_0)

/* Similar to ((t *) (void *) (p)) to cast a pointer. The macro asserts that the pointer has a suitable
 * alignment for type "t". This exists for places where otherwise "-Wcast-align=strict" would issue a
 * warning or if you want to assert that the cast gives a pointer of suitable alignment. */
#define CAST_ALIGN_PTR(t, p)                                    \
        ({                                                      \
                const void *_p = (p);                           \
                assert(((uintptr_t) _p) % alignof(t) == 0); \
                (t *) _p;                                       \
        })