Coverage Report

Created: 2026-08-13 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/jemalloc_shim.h
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
#pragma once
15
16
#if !defined(HAVE_JEMALLOC)
17
18
#include <limits.h>
19
#include <stddef.h>
20
#include <stdint.h>
21
#include <stdlib.h>
22
#include <string.h>
23
#include <strings.h>
24
25
#include <isc/overflow.h>
26
#include <isc/util.h>
27
28
const char *malloc_conf = NULL;
29
30
static size_t
31
369M
get_aligned_size(size_t alignment, size_t size) {
32
  /*
33
   * C23 dropped the requirement that size be an integral multiple of
34
   * alignment, but some implementations still enforce it at runtime,
35
   * so round the size up.
36
   */
37
369M
  return ISC_CHECKED_ADD(size, alignment - 1) & ~(alignment - 1);
38
369M
}
39
40
#ifndef HAVE_FREE_SIZED
41
static void
42
117M
free_sized(void *ptr, size_t size ISC_ATTR_UNUSED) {
43
117M
  free(ptr);
44
117M
}
45
#endif
46
47
#ifndef HAVE_FREE_ALIGNED_SIZED
48
static void
49
free_aligned_sized(void *ptr, size_t alignment ISC_ATTR_UNUSED,
50
33.2k
       size_t size ISC_ATTR_UNUSED) {
51
33.2k
  free(ptr);
52
33.2k
}
53
#endif
54
55
/*
56
 * The MALLOCX_ZERO, MALLOCX_ALIGN and MALLOCX_*_GET macros were taken
57
 * literal from jemalloc_macros.h and jemalloc_internal_types.h headers
58
 * respectively.
59
 */
60
61
117M
#define MALLOCX_ZERO    ((int)0x40)
62
117M
#define MALLOCX_ZERO_GET(flags) ((bool)(flags & MALLOCX_ZERO))
63
64
838M
#define MALLOCX_LG_ALIGN_MASK ((int)0x3f)
65
#if __SIZEOF_POINTER__ == 4
66
#define MALLOCX_ALIGN(a) ((int)(ffs((int)(a)) - 1))
67
#else
68
#define MALLOCX_ALIGN(a)                       \
69
  ((int)(((size_t)(a) < (size_t)INT_MAX) \
70
           ? ffs((int)(a)) - 1     \
71
           : ffs((int)(((size_t)(a)) >> 32)) + 31))
72
#endif
73
#define MALLOCX_ALIGN_GET(flags) \
74
838M
  (((size_t)1) << (flags & MALLOCX_LG_ALIGN_MASK))
75
76
/*
77
 * malloc() already guarantees alignment suitable for any fundamental
78
 * type; only larger alignment requests need the aligned paths below.
79
 */
80
#define MALLOCX_NEEDS_ALIGN(flags) \
81
234M
  (MALLOCX_ALIGN_GET(flags) > _Alignof(max_align_t))
82
83
typedef union {
84
  struct {
85
    size_t size;
86
    int flags;
87
  };
88
  max_align_t __alignment;
89
} size_info;
90
91
/*
92
 * The size_info header sits a multiple of the requested alignment before the
93
 * returned pointer.  The caller passes the matching MALLOCX_ALIGN() flag on
94
 * deallocation too, so the base address is always recomputable from the flags
95
 * and nothing needs to be stored.
96
 */
97
98
static inline size_t
99
369M
get_header_size(int flags) {
100
369M
  return get_aligned_size(MALLOCX_ALIGN_GET(flags), sizeof(size_info));
101
369M
}
102
103
static inline size_info *
104
135M
get_size_info(void *ptr, int flags) {
105
135M
  return (size_info *)((uint8_t *)ptr - get_header_size(flags));
106
135M
}
107
108
static inline void *
109
117M
mallocx(size_t size, int flags) {
110
117M
  size_t alignment = MALLOCX_ALIGN_GET(flags);
111
117M
  size_t header_size = get_header_size(flags);
112
117M
  size_info *si;
113
114
117M
  if (MALLOCX_NEEDS_ALIGN(flags)) {
115
33.3k
    size_t bytes = ISC_CHECKED_ADD(
116
33.3k
      get_aligned_size(alignment, size), header_size);
117
33.3k
    si = aligned_alloc(alignment, bytes);
118
117M
  } else {
119
117M
    si = malloc(ISC_CHECKED_ADD(size, header_size));
120
117M
  }
121
117M
  if (si == NULL) {
122
0
    return NULL;
123
0
  }
124
117M
  si->size = size;
125
117M
  si->flags = flags;
126
127
117M
  void *ptr = (uint8_t *)si + header_size;
128
117M
  if (MALLOCX_ZERO_GET(flags)) {
129
2.89M
    memset(ptr, 0, size);
130
2.89M
  }
131
132
117M
  return ptr;
133
117M
}
134
135
static inline void
136
117M
sdallocx(void *ptr, size_t size, int flags) {
137
117M
  size_info *si = get_size_info(ptr, flags);
138
117M
  size_t alignment = MALLOCX_ALIGN_GET(flags);
139
117M
  size_t header_size = get_header_size(flags);
140
141
117M
  INSIST((flags & MALLOCX_LG_ALIGN_MASK) ==
142
117M
         (si->flags & MALLOCX_LG_ALIGN_MASK));
143
144
117M
  if (MALLOCX_NEEDS_ALIGN(flags)) {
145
33.2k
    size_t bytes = ISC_CHECKED_ADD(
146
33.2k
      get_aligned_size(alignment, size), header_size);
147
33.2k
    free_aligned_sized(si, alignment, bytes);
148
117M
  } else {
149
117M
    free_sized(si, ISC_CHECKED_ADD(si->size, header_size));
150
117M
  }
151
117M
}
152
153
static inline size_t
154
18.1M
sallocx(void *ptr, int flags) {
155
18.1M
  size_info *si = get_size_info(ptr, flags);
156
157
18.1M
  return si[0].size;
158
18.1M
}
159
160
static inline void *
161
4.52k
rallocx(void *ptr, size_t size, int flags) {
162
4.52k
  size_t header_size = get_header_size(flags);
163
4.52k
  size_info *si = get_size_info(ptr, flags);
164
4.52k
  size_t old_size = si->size;
165
166
4.52k
  INSIST((flags & MALLOCX_LG_ALIGN_MASK) ==
167
4.52k
         (si->flags & MALLOCX_LG_ALIGN_MASK));
168
169
4.52k
  if (MALLOCX_NEEDS_ALIGN(flags)) {
170
    /*
171
     * realloc() cannot preserve the requested alignment;
172
     * move the data to a fresh aligned allocation.
173
     */
174
0
    void *new_ptr = mallocx(size, flags & ~MALLOCX_ZERO);
175
0
    if (new_ptr == NULL) {
176
0
      return NULL;
177
0
    }
178
0
    memmove(new_ptr, ptr, ISC_MIN(old_size, size));
179
0
    if (MALLOCX_ZERO_GET(flags) && size > old_size) {
180
0
      memset((uint8_t *)new_ptr + old_size, 0,
181
0
             size - old_size);
182
0
    }
183
0
    sdallocx(ptr, old_size, flags);
184
185
0
    si = get_size_info(new_ptr, flags);
186
0
    si->flags = flags;
187
188
0
    return new_ptr;
189
0
  }
190
191
4.52k
  si = realloc(si, ISC_CHECKED_ADD(size, header_size));
192
4.52k
  if (si == NULL) {
193
0
    return NULL;
194
0
  }
195
4.52k
  si->size = size;
196
4.52k
  si->flags = flags;
197
198
4.52k
  ptr = (uint8_t *)si + header_size;
199
4.52k
  if (MALLOCX_ZERO_GET(flags) && size > old_size) {
200
0
    memset((uint8_t *)ptr + old_size, 0, size - old_size);
201
0
  }
202
203
4.52k
  return ptr;
204
4.52k
}
205
206
#endif /* !defined(HAVE_JEMALLOC) */