Coverage Report

Created: 2025-07-23 06:46

/src/dovecot/src/lib/mempool-system.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2
3
/* @UNSAFE: whole file */
4
5
#include "lib.h"
6
#include "safe-memset.h"
7
#include "mempool.h"
8
9
/*
10
 * The system pool is a thin wrapper around calloc() and free().  It exists
11
 * to allow direct heap usage via the pool API.
12
 *
13
 * Implementation
14
 * ==============
15
 *
16
 * Creation
17
 * --------
18
 *
19
 * The system pool is created statically and therefore is available at any
20
 * time.
21
 *
22
 * Allocation, Reallocation & Freeing
23
 * ----------------------------------
24
 *
25
 * The p_malloc(), p_realloc(), and p_free() calls get directed to calloc(),
26
 * realloc(), and free().  There is no additional per-allocation information
27
 * to track.
28
 *
29
 * Clearing
30
 * --------
31
 *
32
 * Not supported.  Attempting to clear the system pool will result in a
33
 * panic.
34
 *
35
 * Destruction
36
 * -----------
37
 *
38
 * It is not possible to destroy the system pool.  Any attempt to unref the
39
 * pool is a no-op.
40
 */
41
42
#ifndef HAVE_MALLOC_USABLE_SIZE
43
/* no extra includes needed */
44
#elif defined (HAVE_MALLOC_NP_H)
45
#  include <malloc_np.h> /* FreeBSD */
46
#elif defined (HAVE_MALLOC_H)
47
#  include <malloc.h> /* Linux */
48
#endif
49
50
#define CLEAR_CHR 0xde
51
52
static const char *pool_system_get_name(pool_t pool);
53
static void pool_system_ref(pool_t pool);
54
static void pool_system_unref(pool_t *pool);
55
static void *pool_system_malloc(pool_t pool, size_t size);
56
static void *pool_system_realloc(pool_t pool, void *mem,
57
         size_t old_size, size_t new_size);
58
static void pool_system_clear(pool_t pool);
59
static size_t pool_system_get_max_easy_alloc_size(pool_t pool);
60
61
static struct pool_vfuncs static_system_pool_vfuncs = {
62
  pool_system_get_name,
63
64
  pool_system_ref,
65
  pool_system_unref,
66
67
  pool_system_malloc,
68
  pool_system_free,
69
70
  pool_system_realloc,
71
72
  pool_system_clear,
73
  pool_system_get_max_easy_alloc_size
74
};
75
76
struct pool static_system_pool = {
77
  .v = &static_system_pool_vfuncs,
78
79
  .alloconly_pool = FALSE,
80
  .datastack_pool = FALSE
81
};
82
83
pool_t system_pool = &static_system_pool;
84
85
static const char *pool_system_get_name(pool_t pool ATTR_UNUSED)
86
0
{
87
0
  return "system";
88
0
}
89
90
static void pool_system_ref(pool_t pool ATTR_UNUSED)
91
0
{
92
0
}
93
94
static void pool_system_unref(pool_t *pool ATTR_UNUSED)
95
0
{
96
0
}
97
98
static void *pool_system_malloc(pool_t pool ATTR_UNUSED, size_t size)
99
2.84M
{
100
2.84M
  void *mem;
101
#ifdef DEBUG
102
  int old_errno = errno;
103
#endif
104
105
2.84M
  mem = calloc(size, 1);
106
2.84M
  if (unlikely(mem == NULL)) {
107
0
    i_fatal_status(FATAL_OUTOFMEM, "pool_system_malloc(%zu): "
108
0
             "Out of memory", size);
109
0
  }
110
#ifdef DEBUG
111
  /* we rely on errno not changing. it shouldn't. */
112
  i_assert(errno == old_errno);
113
#endif
114
2.84M
  return mem;
115
2.84M
}
116
117
void pool_system_free(pool_t pool ATTR_UNUSED, void *mem ATTR_UNUSED)
118
2.84M
{
119
#ifdef DEBUG
120
  int old_errno = errno;
121
#endif
122
#if defined(HAVE_MALLOC_USABLE_SIZE) && defined(DEBUG)
123
  safe_memset(mem, CLEAR_CHR, malloc_usable_size(mem));
124
#endif
125
2.84M
  free(mem);
126
#ifdef DEBUG
127
  /* we rely on errno not changing. it shouldn't. */
128
  i_assert(errno == old_errno);
129
#endif
130
2.84M
}
131
132
static void *pool_system_realloc(pool_t pool ATTR_UNUSED, void *mem,
133
         size_t old_size, size_t new_size)
134
3.08k
{
135
3.08k
#if defined(HAVE_MALLOC_USABLE_SIZE)
136
3.08k
  i_assert(old_size == SIZE_MAX || mem == NULL ||
137
3.08k
     old_size <= malloc_usable_size(mem));
138
3.08k
#endif
139
140
3.08k
  mem = realloc(mem, new_size);
141
3.08k
  if (unlikely(mem == NULL)) {
142
0
    i_fatal_status(FATAL_OUTOFMEM, "pool_system_realloc(%zu): "
143
0
             "Out of memory", new_size);
144
0
  }
145
146
3.08k
  if (old_size < new_size) {
147
    /* clear new data */
148
3.08k
    memset((char *) mem + old_size, 0, new_size - old_size);
149
3.08k
  }
150
151
3.08k
  return mem;
152
3.08k
}
153
154
static void ATTR_NORETURN
155
pool_system_clear(pool_t pool ATTR_UNUSED)
156
0
{
157
0
  i_panic("pool_system_clear() must not be called");
158
0
}
159
160
static size_t pool_system_get_max_easy_alloc_size(pool_t pool ATTR_UNUSED)
161
3.08k
{
162
3.08k
  return 0;
163
3.08k
}