Bug Summary

File:build-scan/../src/journal/mmap-cache.c
Warning:line 513, column 16
1st function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name mmap-cache.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/journal/libjournal-client.a.p -I src/journal -I ../src/journal -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility default -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/journal/mmap-cache.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno(*__errno_location ()).h>
4#include <stdlib.h>
5#include <sys/mman.h>
6
7#include "alloc-util.h"
8#include "fd-util.h"
9#include "hashmap.h"
10#include "list.h"
11#include "log.h"
12#include "macro.h"
13#include "mmap-cache.h"
14#include "sigbus.h"
15#include "util.h"
16
17typedef struct Window Window;
18typedef struct Context Context;
19
20struct Window {
21 MMapCache *cache;
22
23 bool_Bool invalidated:1;
24 bool_Bool keep_always:1;
25 bool_Bool in_unused:1;
26
27 int prot;
28 void *ptr;
29 uint64_t offset;
30 size_t size;
31
32 MMapFileDescriptor *fd;
33
34 LIST_FIELDS(Window, by_fd)Window *by_fd_next, *by_fd_prev;
35 LIST_FIELDS(Window, unused)Window *unused_next, *unused_prev;
36
37 LIST_HEAD(Context, contexts)Context *contexts;
38};
39
40struct Context {
41 MMapCache *cache;
42 unsigned id;
43 Window *window;
44
45 LIST_FIELDS(Context, by_window)Context *by_window_next, *by_window_prev;
46};
47
48struct MMapFileDescriptor {
49 MMapCache *cache;
50 int fd;
51 bool_Bool sigbus;
52 LIST_HEAD(Window, windows)Window *windows;
53};
54
55struct MMapCache {
56 int n_ref;
57 unsigned n_windows;
58
59 unsigned n_hit, n_missed;
60
61 Hashmap *fds;
62 Context *contexts[MMAP_CACHE_MAX_CONTEXTS9];
63
64 LIST_HEAD(Window, unused)Window *unused;
65 Window *last_unused;
66};
67
68#define WINDOWS_MIN64 64
69
70#if ENABLE_DEBUG_MMAP_CACHE0
71/* Tiny windows increase mmap activity and the chance of exposing unsafe use. */
72# define WINDOW_SIZE(8ULL*1024ULL*1024ULL) (page_size())
73#else
74# define WINDOW_SIZE(8ULL*1024ULL*1024ULL) (8ULL*1024ULL*1024ULL)
75#endif
76
77MMapCache* mmap_cache_new(void) {
78 MMapCache *m;
79
80 m = new0(MMapCache, 1)((MMapCache*) calloc((1), sizeof(MMapCache)));
81 if (!m)
82 return NULL((void*)0);
83
84 m->n_ref = 1;
85 return m;
86}
87
88MMapCache* mmap_cache_ref(MMapCache *m) {
89 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 89,
__PRETTY_FUNCTION__); } while (0)
;
90 assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c"
, 90, __PRETTY_FUNCTION__); } while (0)
;
91
92 m->n_ref++;
93 return m;
94}
95
96static void window_unlink(Window *w) {
97 Context *c;
98
99 assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 99,
__PRETTY_FUNCTION__); } while (0)
;
100
101 if (w->ptr)
102 munmap(w->ptr, w->size);
103
104 if (w->fd)
105 LIST_REMOVE(by_fd, w->fd->windows, w)do { typeof(*(w->fd->windows)) **_head = &(w->fd
->windows), *_item = (w); do { if ((__builtin_expect(!!(!(
_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"
), "../src/journal/mmap-cache.c", 105, __PRETTY_FUNCTION__); }
while (0); if (_item->by_fd_next) _item->by_fd_next->
by_fd_prev = _item->by_fd_prev; if (_item->by_fd_prev) _item
->by_fd_prev->by_fd_next = _item->by_fd_next; else {
do { if ((__builtin_expect(!!(!(*_head == _item)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("*_head == _item"), "../src/journal/mmap-cache.c"
, 105, __PRETTY_FUNCTION__); } while (0); *_head = _item->
by_fd_next; } _item->by_fd_next = _item->by_fd_prev = (
(void*)0); } while (0)
;
106
107 if (w->in_unused) {
108 if (w->cache->last_unused == w)
109 w->cache->last_unused = w->unused_prev;
110
111 LIST_REMOVE(unused, w->cache->unused, w)do { typeof(*(w->cache->unused)) **_head = &(w->
cache->unused), *_item = (w); do { if ((__builtin_expect(!
!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, (
"_item"), "../src/journal/mmap-cache.c", 111, __PRETTY_FUNCTION__
); } while (0); if (_item->unused_next) _item->unused_next
->unused_prev = _item->unused_prev; if (_item->unused_prev
) _item->unused_prev->unused_next = _item->unused_next
; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item"
), "../src/journal/mmap-cache.c", 111, __PRETTY_FUNCTION__); }
while (0); *_head = _item->unused_next; } _item->unused_next
= _item->unused_prev = ((void*)0); } while (0)
;
112 }
113
114 LIST_FOREACH(by_window, c, w->contexts)for ((c) = (w->contexts); (c); (c) = (c)->by_window_next
)
{
115 assert(c->window == w)do { if ((__builtin_expect(!!(!(c->window == w)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c->window == w"), "../src/journal/mmap-cache.c"
, 115, __PRETTY_FUNCTION__); } while (0)
;
116 c->window = NULL((void*)0);
117 }
118}
119
120static void window_invalidate(Window *w) {
121 assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 121
, __PRETTY_FUNCTION__); } while (0)
;
122
123 if (w->invalidated)
124 return;
125
126 /* Replace the window with anonymous pages. This is useful
127 * when we hit a SIGBUS and want to make sure the file cannot
128 * trigger any further SIGBUS, possibly overrunning the sigbus
129 * queue. */
130
131 assert_se(mmap(w->ptr, w->size, w->prot, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) == w->ptr)do { if ((__builtin_expect(!!(!(mmap(w->ptr, w->size, w
->prot, 0x02|0x20|0x10, -1, 0) == w->ptr)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("mmap(w->ptr, w->size, w->prot, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) == w->ptr"
), "../src/journal/mmap-cache.c", 131, __PRETTY_FUNCTION__); }
while (0)
;
132 w->invalidated = true1;
133}
134
135static void window_free(Window *w) {
136 assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 136
, __PRETTY_FUNCTION__); } while (0)
;
137
138 window_unlink(w);
139 w->cache->n_windows--;
140 free(w);
141}
142
143_pure___attribute__ ((pure)) static inline bool_Bool window_matches(Window *w, int prot, uint64_t offset, size_t size) {
144 assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 144
, __PRETTY_FUNCTION__); } while (0)
;
145 assert(size > 0)do { if ((__builtin_expect(!!(!(size > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("size > 0"), "../src/journal/mmap-cache.c"
, 145, __PRETTY_FUNCTION__); } while (0)
;
146
147 return
148 prot == w->prot &&
149 offset >= w->offset &&
150 offset + size <= w->offset + w->size;
151}
152
153_pure___attribute__ ((pure)) static bool_Bool window_matches_fd(Window *w, MMapFileDescriptor *f, int prot, uint64_t offset, size_t size) {
154 assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 154
, __PRETTY_FUNCTION__); } while (0)
;
155 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 155
, __PRETTY_FUNCTION__); } while (0)
;
156
157 return
158 w->fd &&
159 f->fd == w->fd->fd &&
160 window_matches(w, prot, offset, size);
161}
162
163static Window *window_add(MMapCache *m, MMapFileDescriptor *f, int prot, bool_Bool keep_always, uint64_t offset, size_t size, void *ptr) {
164 Window *w;
165
166 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 166
, __PRETTY_FUNCTION__); } while (0)
;
167 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 167
, __PRETTY_FUNCTION__); } while (0)
;
168
169 if (!m->last_unused || m->n_windows <= WINDOWS_MIN64) {
170
171 /* Allocate a new window */
172 w = new0(Window, 1)((Window*) calloc((1), sizeof(Window)));
173 if (!w)
174 return NULL((void*)0);
175 m->n_windows++;
176 } else {
177
178 /* Reuse an existing one */
179 w = m->last_unused;
180 window_unlink(w);
181 zero(*w)(({ size_t _l_ = (sizeof(*w)); void *_x_ = (&(*w)); _l_ ==
0 ? _x_ : memset(_x_, 0, _l_); }))
;
182 }
183
184 w->cache = m;
185 w->fd = f;
186 w->prot = prot;
187 w->keep_always = keep_always;
188 w->offset = offset;
189 w->size = size;
190 w->ptr = ptr;
191
192 LIST_PREPEND(by_fd, f->windows, w)do { typeof(*(f->windows)) **_head = &(f->windows),
*_item = (w); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_item"), "../src/journal/mmap-cache.c",
192, __PRETTY_FUNCTION__); } while (0); if ((_item->by_fd_next
= *_head)) _item->by_fd_next->by_fd_prev = _item; _item
->by_fd_prev = ((void*)0); *_head = _item; } while (0)
;
193
194 return w;
195}
196
197static void context_detach_window(Context *c) {
198 Window *w;
199
200 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/journal/mmap-cache.c", 200
, __PRETTY_FUNCTION__); } while (0)
;
201
202 if (!c->window)
203 return;
204
205 w = TAKE_PTR(c->window)({ typeof(c->window) _ptr_ = (c->window); (c->window
) = ((void*)0); _ptr_; })
;
206 LIST_REMOVE(by_window, w->contexts, c)do { typeof(*(w->contexts)) **_head = &(w->contexts
), *_item = (c); do { if ((__builtin_expect(!!(!(_item)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/journal/mmap-cache.c"
, 206, __PRETTY_FUNCTION__); } while (0); if (_item->by_window_next
) _item->by_window_next->by_window_prev = _item->by_window_prev
; if (_item->by_window_prev) _item->by_window_prev->
by_window_next = _item->by_window_next; else { do { if ((__builtin_expect
(!!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("*_head == _item"), "../src/journal/mmap-cache.c", 206, __PRETTY_FUNCTION__
); } while (0); *_head = _item->by_window_next; } _item->
by_window_next = _item->by_window_prev = ((void*)0); } while
(0)
;
207
208 if (!w->contexts && !w->keep_always) {
209 /* Not used anymore? */
210#if ENABLE_DEBUG_MMAP_CACHE0
211 /* Unmap unused windows immediately to expose use-after-unmap
212 * by SIGSEGV. */
213 window_free(w);
214#else
215 LIST_PREPEND(unused, c->cache->unused, w)do { typeof(*(c->cache->unused)) **_head = &(c->
cache->unused), *_item = (w); do { if ((__builtin_expect(!
!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, (
"_item"), "../src/journal/mmap-cache.c", 215, __PRETTY_FUNCTION__
); } while (0); if ((_item->unused_next = *_head)) _item->
unused_next->unused_prev = _item; _item->unused_prev = (
(void*)0); *_head = _item; } while (0)
;
216 if (!c->cache->last_unused)
217 c->cache->last_unused = w;
218
219 w->in_unused = true1;
220#endif
221 }
222}
223
224static void context_attach_window(Context *c, Window *w) {
225 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/journal/mmap-cache.c", 225
, __PRETTY_FUNCTION__); } while (0)
;
226 assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 226
, __PRETTY_FUNCTION__); } while (0)
;
227
228 if (c->window == w)
229 return;
230
231 context_detach_window(c);
232
233 if (w->in_unused) {
234 /* Used again? */
235 LIST_REMOVE(unused, c->cache->unused, w)do { typeof(*(c->cache->unused)) **_head = &(c->
cache->unused), *_item = (w); do { if ((__builtin_expect(!
!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, (
"_item"), "../src/journal/mmap-cache.c", 235, __PRETTY_FUNCTION__
); } while (0); if (_item->unused_next) _item->unused_next
->unused_prev = _item->unused_prev; if (_item->unused_prev
) _item->unused_prev->unused_next = _item->unused_next
; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item"
), "../src/journal/mmap-cache.c", 235, __PRETTY_FUNCTION__); }
while (0); *_head = _item->unused_next; } _item->unused_next
= _item->unused_prev = ((void*)0); } while (0)
;
236 if (c->cache->last_unused == w)
237 c->cache->last_unused = w->unused_prev;
238
239 w->in_unused = false0;
240 }
241
242 c->window = w;
243 LIST_PREPEND(by_window, w->contexts, c)do { typeof(*(w->contexts)) **_head = &(w->contexts
), *_item = (c); do { if ((__builtin_expect(!!(!(_item)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/journal/mmap-cache.c"
, 243, __PRETTY_FUNCTION__); } while (0); if ((_item->by_window_next
= *_head)) _item->by_window_next->by_window_prev = _item
; _item->by_window_prev = ((void*)0); *_head = _item; } while
(0)
;
244}
245
246static Context *context_add(MMapCache *m, unsigned id) {
247 Context *c;
248
249 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 249
, __PRETTY_FUNCTION__); } while (0)
;
250
251 c = m->contexts[id];
252 if (c)
253 return c;
254
255 c = new0(Context, 1)((Context*) calloc((1), sizeof(Context)));
256 if (!c)
257 return NULL((void*)0);
258
259 c->cache = m;
260 c->id = id;
261
262 assert(!m->contexts[id])do { if ((__builtin_expect(!!(!(!m->contexts[id])),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("!m->contexts[id]"), "../src/journal/mmap-cache.c"
, 262, __PRETTY_FUNCTION__); } while (0)
;
263 m->contexts[id] = c;
264
265 return c;
266}
267
268static void context_free(Context *c) {
269 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/journal/mmap-cache.c", 269
, __PRETTY_FUNCTION__); } while (0)
;
270
271 context_detach_window(c);
272
273 if (c->cache) {
274 assert(c->cache->contexts[c->id] == c)do { if ((__builtin_expect(!!(!(c->cache->contexts[c->
id] == c)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("c->cache->contexts[c->id] == c"
), "../src/journal/mmap-cache.c", 274, __PRETTY_FUNCTION__); }
while (0)
;
275 c->cache->contexts[c->id] = NULL((void*)0);
276 }
277
278 free(c);
279}
280
281static void mmap_cache_free(MMapCache *m) {
282 int i;
283
284 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 284
, __PRETTY_FUNCTION__); } while (0)
;
285
286 for (i = 0; i < MMAP_CACHE_MAX_CONTEXTS9; i++)
287 if (m->contexts[i])
288 context_free(m->contexts[i]);
289
290 hashmap_free(m->fds);
291
292 while (m->unused)
293 window_free(m->unused);
294
295 free(m);
296}
297
298MMapCache* mmap_cache_unref(MMapCache *m) {
299
300 if (!m)
301 return NULL((void*)0);
302
303 assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c"
, 303, __PRETTY_FUNCTION__); } while (0)
;
304
305 m->n_ref--;
306 if (m->n_ref == 0)
307 mmap_cache_free(m);
308
309 return NULL((void*)0);
310}
311
312static int make_room(MMapCache *m) {
313 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 313
, __PRETTY_FUNCTION__); } while (0)
;
314
315 if (!m->last_unused)
316 return 0;
317
318 window_free(m->last_unused);
319 return 1;
320}
321
322static int try_context(
323 MMapCache *m,
324 MMapFileDescriptor *f,
325 int prot,
326 unsigned context,
327 bool_Bool keep_always,
328 uint64_t offset,
329 size_t size,
330 void **ret,
331 size_t *ret_size) {
332
333 Context *c;
334
335 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 335
, __PRETTY_FUNCTION__); } while (0)
;
336 assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c"
, 336, __PRETTY_FUNCTION__); } while (0)
;
337 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 337
, __PRETTY_FUNCTION__); } while (0)
;
338 assert(size > 0)do { if ((__builtin_expect(!!(!(size > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("size > 0"), "../src/journal/mmap-cache.c"
, 338, __PRETTY_FUNCTION__); } while (0)
;
339 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/journal/mmap-cache.c", 339
, __PRETTY_FUNCTION__); } while (0)
;
340
341 c = m->contexts[context];
342 if (!c)
343 return 0;
344
345 assert(c->id == context)do { if ((__builtin_expect(!!(!(c->id == context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c->id == context"), "../src/journal/mmap-cache.c"
, 345, __PRETTY_FUNCTION__); } while (0)
;
346
347 if (!c->window)
348 return 0;
349
350 if (!window_matches_fd(c->window, f, prot, offset, size)) {
351
352 /* Drop the reference to the window, since it's unnecessary now */
353 context_detach_window(c);
354 return 0;
355 }
356
357 if (c->window->fd->sigbus)
358 return -EIO5;
359
360 c->window->keep_always = c->window->keep_always || keep_always;
361
362 *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset);
363 if (ret_size)
364 *ret_size = c->window->size - (offset - c->window->offset);
365
366 return 1;
367}
368
369static int find_mmap(
370 MMapCache *m,
371 MMapFileDescriptor *f,
372 int prot,
373 unsigned context,
374 bool_Bool keep_always,
375 uint64_t offset,
376 size_t size,
377 void **ret,
378 size_t *ret_size) {
379
380 Window *w;
381 Context *c;
382
383 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 383
, __PRETTY_FUNCTION__); } while (0)
;
384 assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c"
, 384, __PRETTY_FUNCTION__); } while (0)
;
385 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 385
, __PRETTY_FUNCTION__); } while (0)
;
386 assert(size > 0)do { if ((__builtin_expect(!!(!(size > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("size > 0"), "../src/journal/mmap-cache.c"
, 386, __PRETTY_FUNCTION__); } while (0)
;
387
388 if (f->sigbus)
389 return -EIO5;
390
391 LIST_FOREACH(by_fd, w, f->windows)for ((w) = (f->windows); (w); (w) = (w)->by_fd_next)
392 if (window_matches(w, prot, offset, size))
393 break;
394
395 if (!w)
396 return 0;
397
398 c = context_add(m, context);
399 if (!c)
400 return -ENOMEM12;
401
402 context_attach_window(c, w);
403 w->keep_always = w->keep_always || keep_always;
404
405 *ret = (uint8_t*) w->ptr + (offset - w->offset);
406 if (ret_size)
407 *ret_size = w->size - (offset - w->offset);
408
409 return 1;
410}
411
412static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int prot, int flags, uint64_t offset, size_t size, void **res) {
413 void *ptr;
414
415 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 415
, __PRETTY_FUNCTION__); } while (0)
;
38
Taking false branch
39
Loop condition is false. Exiting loop
416 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 416
, __PRETTY_FUNCTION__); } while (0)
;
40
Taking false branch
41
Loop condition is false. Exiting loop
417 assert(res)do { if ((__builtin_expect(!!(!(res)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("res"), "../src/journal/mmap-cache.c", 417
, __PRETTY_FUNCTION__); } while (0)
;
42
Taking false branch
43
Loop condition is false. Exiting loop
418
419 for (;;) {
44
Loop condition is true. Entering loop body
420 int r;
421
422 ptr = mmap(addr, size, prot, flags, f->fd, offset);
423 if (ptr != MAP_FAILED((void *) -1))
45
Assuming the condition is false
46
Taking false branch
424 break;
425 if (errno(*__errno_location ()) != ENOMEM12)
47
Assuming the condition is true
48
Taking true branch
426 return negative_errno();
49
Returning without writing to '*res'
427
428 r = make_room(m);
429 if (r < 0)
430 return r;
431 if (r == 0)
432 return -ENOMEM12;
433 }
434
435 *res = ptr;
436 return 0;
437}
438
439static int add_mmap(
440 MMapCache *m,
441 MMapFileDescriptor *f,
442 int prot,
443 unsigned context,
444 bool_Bool keep_always,
445 uint64_t offset,
446 size_t size,
447 struct stat *st,
448 void **ret,
449 size_t *ret_size) {
450
451 uint64_t woffset, wsize;
452 Context *c;
453 Window *w;
454 void *d;
22
'd' declared without an initial value
455 int r;
456
457 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 457
, __PRETTY_FUNCTION__); } while (0)
;
23
Taking false branch
24
Loop condition is false. Exiting loop
458 assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c"
, 458, __PRETTY_FUNCTION__); } while (0)
;
25
Taking false branch
26
Loop condition is false. Exiting loop
459 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 459
, __PRETTY_FUNCTION__); } while (0)
;
27
Taking false branch
28
Loop condition is false. Exiting loop
460 assert(size > 0)do { if ((__builtin_expect(!!(!(size > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("size > 0"), "../src/journal/mmap-cache.c"
, 460, __PRETTY_FUNCTION__); } while (0)
;
29
Taking false branch
30
Loop condition is false. Exiting loop
461 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/journal/mmap-cache.c", 461
, __PRETTY_FUNCTION__); } while (0)
;
31
Taking false branch
32
Loop condition is false. Exiting loop
462
463 woffset = offset & ~((uint64_t) page_size() - 1ULL);
464 wsize = size + (offset - woffset);
465 wsize = PAGE_ALIGN(wsize)ALIGN_TO((wsize), page_size());
466
467 if (wsize < WINDOW_SIZE(8ULL*1024ULL*1024ULL)) {
33
Assuming the condition is false
34
Taking false branch
468 uint64_t delta;
469
470 delta = PAGE_ALIGN((WINDOW_SIZE - wsize) / 2)ALIGN_TO((((8ULL*1024ULL*1024ULL) - wsize) / 2), page_size());
471
472 if (delta > offset)
473 woffset = 0;
474 else
475 woffset -= delta;
476
477 wsize = WINDOW_SIZE(8ULL*1024ULL*1024ULL);
478 }
479
480 if (st) {
35
Assuming 'st' is null
36
Taking false branch
481 /* Memory maps that are larger then the files
482 underneath have undefined behavior. Hence, clamp
483 things to the file size if we know it */
484
485 if (woffset >= (uint64_t) st->st_size)
486 return -EADDRNOTAVAIL99;
487
488 if (woffset + wsize > (uint64_t) st->st_size)
489 wsize = PAGE_ALIGN(st->st_size - woffset)ALIGN_TO((st->st_size - woffset), page_size());
490 }
491
492 r = mmap_try_harder(m, NULL((void*)0), f, prot, MAP_SHARED0x01, woffset, wsize, &d);
37
Calling 'mmap_try_harder'
50
Returning from 'mmap_try_harder'
493 if (r < 0)
51
Assuming 'r' is >= 0
52
Taking false branch
494 return r;
495
496 c = context_add(m, context);
497 if (!c)
53
Assuming 'c' is null
54
Taking true branch
498 goto outofmem;
55
Control jumps to line 513
499
500 w = window_add(m, f, prot, keep_always, woffset, wsize, d);
501 if (!w)
502 goto outofmem;
503
504 context_attach_window(c, w);
505
506 *ret = (uint8_t*) w->ptr + (offset - w->offset);
507 if (ret_size)
508 *ret_size = w->size - (offset - w->offset);
509
510 return 1;
511
512outofmem:
513 (void) munmap(d, wsize);
56
1st function call argument is an uninitialized value
514 return -ENOMEM12;
515}
516
517int mmap_cache_get(
518 MMapCache *m,
519 MMapFileDescriptor *f,
520 int prot,
521 unsigned context,
522 bool_Bool keep_always,
523 uint64_t offset,
524 size_t size,
525 struct stat *st,
526 void **ret,
527 size_t *ret_size) {
528
529 int r;
530
531 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 531
, __PRETTY_FUNCTION__); } while (0)
;
1
Assuming 'm' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
532 assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c"
, 532, __PRETTY_FUNCTION__); } while (0)
;
4
Assuming field 'n_ref' is > 0
5
Taking false branch
6
Loop condition is false. Exiting loop
533 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 533
, __PRETTY_FUNCTION__); } while (0)
;
7
Assuming 'f' is non-null
8
Taking false branch
9
Loop condition is false. Exiting loop
534 assert(size > 0)do { if ((__builtin_expect(!!(!(size > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("size > 0"), "../src/journal/mmap-cache.c"
, 534, __PRETTY_FUNCTION__); } while (0)
;
10
Assuming 'size' is > 0
11
Taking false branch
12
Loop condition is false. Exiting loop
535 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/journal/mmap-cache.c", 535
, __PRETTY_FUNCTION__); } while (0)
;
13
Assuming 'ret' is non-null
14
Taking false branch
15
Loop condition is false. Exiting loop
536 assert(context < MMAP_CACHE_MAX_CONTEXTS)do { if ((__builtin_expect(!!(!(context < 9)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context < MMAP_CACHE_MAX_CONTEXTS"),
"../src/journal/mmap-cache.c", 536, __PRETTY_FUNCTION__); } while
(0)
;
16
Assuming 'context' is < 9
17
Taking false branch
18
Loop condition is false. Exiting loop
537
538 /* Check whether the current context is the right one already */
539 r = try_context(m, f, prot, context, keep_always, offset, size, ret, ret_size);
540 if (r
18.1
'r' is equal to 0
!= 0) {
19
Taking false branch
541 m->n_hit++;
542 return r;
543 }
544
545 /* Search for a matching mmap */
546 r = find_mmap(m, f, prot, context, keep_always, offset, size, ret, ret_size);
547 if (r
19.1
'r' is equal to 0
!= 0) {
20
Taking false branch
548 m->n_hit++;
549 return r;
550 }
551
552 m->n_missed++;
553
554 /* Create a new mmap */
555 return add_mmap(m, f, prot, context, keep_always, offset, size, st, ret, ret_size);
21
Calling 'add_mmap'
556}
557
558unsigned mmap_cache_get_hit(MMapCache *m) {
559 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 559
, __PRETTY_FUNCTION__); } while (0)
;
560
561 return m->n_hit;
562}
563
564unsigned mmap_cache_get_missed(MMapCache *m) {
565 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 565
, __PRETTY_FUNCTION__); } while (0)
;
566
567 return m->n_missed;
568}
569
570static void mmap_cache_process_sigbus(MMapCache *m) {
571 bool_Bool found = false0;
572 MMapFileDescriptor *f;
573 Iterator i;
574 int r;
575
576 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 576
, __PRETTY_FUNCTION__); } while (0)
;
577
578 /* Iterate through all triggered pages and mark their files as
579 * invalidated */
580 for (;;) {
581 bool_Bool ours;
582 void *addr;
583
584 r = sigbus_pop(&addr);
585 if (_likely_(r == 0)(__builtin_expect(!!(r == 0),1)))
586 break;
587 if (r < 0) {
588 log_error_errno(r, "SIGBUS handling failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/journal/mmap-cache.c", 588, __func__, "SIGBUS handling failed: %m"
) : -abs(_e); })
;
589 abort();
590 }
591
592 ours = false0;
593 HASHMAP_FOREACH(f, m->fds, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); hashmap_iterate((m->fds), &(
i), (void**)&(f), ((void*)0)); )
{
594 Window *w;
595
596 LIST_FOREACH(by_fd, w, f->windows)for ((w) = (f->windows); (w); (w) = (w)->by_fd_next) {
597 if ((uint8_t*) addr >= (uint8_t*) w->ptr &&
598 (uint8_t*) addr < (uint8_t*) w->ptr + w->size) {
599 found = ours = f->sigbus = true1;
600 break;
601 }
602 }
603
604 if (ours)
605 break;
606 }
607
608 /* Didn't find a matching window, give up */
609 if (!ours) {
610 log_error("Unknown SIGBUS page, aborting.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/journal/mmap-cache.c", 610, __func__, "Unknown SIGBUS page, aborting."
) : -abs(_e); })
;
611 abort();
612 }
613 }
614
615 /* The list of triggered pages is now empty. Now, let's remap
616 * all windows of the triggered file to anonymous maps, so
617 * that no page of the file in question is triggered again, so
618 * that we can be sure not to hit the queue size limit. */
619 if (_likely_(!found)(__builtin_expect(!!(!found),1)))
620 return;
621
622 HASHMAP_FOREACH(f, m->fds, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); hashmap_iterate((m->fds), &(
i), (void**)&(f), ((void*)0)); )
{
623 Window *w;
624
625 if (!f->sigbus)
626 continue;
627
628 LIST_FOREACH(by_fd, w, f->windows)for ((w) = (f->windows); (w); (w) = (w)->by_fd_next)
629 window_invalidate(w);
630 }
631}
632
633bool_Bool mmap_cache_got_sigbus(MMapCache *m, MMapFileDescriptor *f) {
634 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 634
, __PRETTY_FUNCTION__); } while (0)
;
635 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 635
, __PRETTY_FUNCTION__); } while (0)
;
636
637 mmap_cache_process_sigbus(m);
638
639 return f->sigbus;
640}
641
642MMapFileDescriptor* mmap_cache_add_fd(MMapCache *m, int fd) {
643 MMapFileDescriptor *f;
644 int r;
645
646 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 646
, __PRETTY_FUNCTION__); } while (0)
;
647 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/journal/mmap-cache.c"
, 647, __PRETTY_FUNCTION__); } while (0)
;
648
649 f = hashmap_get(m->fds, FD_TO_PTR(fd)((void *) ((intptr_t) ((fd)+1))));
650 if (f)
651 return f;
652
653 r = hashmap_ensure_allocated(&m->fds, NULL)internal_hashmap_ensure_allocated(&m->fds, ((void*)0) );
654 if (r < 0)
655 return NULL((void*)0);
656
657 f = new0(MMapFileDescriptor, 1)((MMapFileDescriptor*) calloc((1), sizeof(MMapFileDescriptor)
))
;
658 if (!f)
659 return NULL((void*)0);
660
661 f->cache = m;
662 f->fd = fd;
663
664 r = hashmap_put(m->fds, FD_TO_PTR(fd)((void *) ((intptr_t) ((fd)+1))), f);
665 if (r < 0)
666 return mfree(f);
667
668 return f;
669}
670
671void mmap_cache_free_fd(MMapCache *m, MMapFileDescriptor *f) {
672 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 672
, __PRETTY_FUNCTION__); } while (0)
;
673 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 673
, __PRETTY_FUNCTION__); } while (0)
;
674
675 /* Make sure that any queued SIGBUS are first dispatched, so
676 * that we don't end up with a SIGBUS entry we cannot relate
677 * to any existing memory map */
678
679 mmap_cache_process_sigbus(m);
680
681 while (f->windows)
682 window_free(f->windows);
683
684 if (f->cache)
685 assert_se(hashmap_remove(f->cache->fds, FD_TO_PTR(f->fd)))do { if ((__builtin_expect(!!(!(hashmap_remove(f->cache->
fds, ((void *) ((intptr_t) ((f->fd)+1)))))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("hashmap_remove(f->cache->fds, FD_TO_PTR(f->fd))"
), "../src/journal/mmap-cache.c", 685, __PRETTY_FUNCTION__); }
while (0)
;
686
687 free(f);
688}