GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/util/smalloc.h
Date: 2025-08-31 02:39:21
Exec Total Coverage
Lines: 58 58 100.0%
Branches: 12 28 42.9%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * Ensures that cvmfs aborts on out-of-memory errors.
5 */
6
7 #ifndef CVMFS_UTIL_SMALLOC_H_
8 #define CVMFS_UTIL_SMALLOC_H_
9
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <sys/mman.h>
13 #include <sys/types.h>
14
15 #include <cassert>
16 // #include <cstdio>
17
18 #include <limits>
19
20 #ifdef __APPLE__
21 #define PLATFORM_MAP_ANONYMOUS MAP_ANON
22 #else
23 #define PLATFORM_MAP_ANONYMOUS MAP_ANONYMOUS
24 #endif
25
26
27 #ifdef CVMFS_NAMESPACE_GUARD
28 namespace CVMFS_NAMESPACE_GUARD {
29 #endif
30
31 // Checkerboard marker (binary 101010...)
32 const uint32_t kMemMarker = 0xAAAAAAAA;
33
34 /**
35 * Round up size to the next larger multiple of 8. This is used to enforce
36 * 8-byte alignment.
37 */
38 287340402 static inline uint64_t RoundUp8(const uint64_t size) {
39 287340402 return (size + 7) & ~static_cast<uint64_t>(7);
40 }
41
42 22774524 static inline void * __attribute__((used)) smalloc(size_t size) {
43 22774524 void *mem = NULL;
44 #ifdef CVMFS_SUPPRESS_ASSERTS
45 do {
46 #endif
47 22774524 mem = malloc(size);
48 #ifdef CVMFS_SUPPRESS_ASSERTS
49 } while ((size > 0) && (mem == NULL));
50 #endif
51
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 22774524 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
22774524 assert((mem || (size == 0)) && "Out Of Memory");
52 22774524 return mem;
53 }
54
55 2743219 static inline void * __attribute__((used)) srealloc(void *ptr, size_t size) {
56 2743219 void *mem = NULL;
57
58 #ifdef CVMFS_SUPPRESS_ASSERTS
59 do {
60 #endif
61 2743219 mem = realloc(ptr, size);
62 #ifdef CVMFS_SUPPRESS_ASSERTS
63 } while ((size > 0) && (mem == NULL));
64 #endif
65
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2743219 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2743219 assert((mem || (size == 0)) && "Out Of Memory");
66 2743219 return mem;
67 }
68
69 5804 static inline void * __attribute__((used)) scalloc(size_t count, size_t size) {
70 5804 void *mem = NULL;
71
72 #ifdef CVMFS_SUPPRESS_ASSERTS
73 do {
74 #endif
75 5804 mem = calloc(count, size);
76 #ifdef CVMFS_SUPPRESS_ASSERTS
77 } while ((count * size > 0) && (mem == NULL));
78 #endif
79
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5804 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
5804 assert((mem || ((count * size) == 0)) && "Out Of Memory");
80 5804 return mem;
81 }
82
83 144020 static inline void * __attribute__((used)) smmap(size_t size) {
84 // TODO(reneme): make page size platform independent
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 144020 times.
144020 assert(size > 0);
86
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 144020 times.
144020 assert(size < std::numeric_limits<size_t>::max() - 4096);
87
88 144020 const int anonymous_fd = -1;
89 144020 const off_t offset = 0;
90 144020 const size_t pages = ((size + 2 * sizeof(size_t)) + 4095)
91 / 4096; // round to full page
92 144020 unsigned char *mem = NULL;
93
94 #ifdef CVMFS_SUPPRESS_ASSERTS
95 do {
96 #endif
97 mem = static_cast<unsigned char *>(
98 144020 mmap(NULL,
99 pages * 4096,
100 PROT_READ | PROT_WRITE,
101 MAP_PRIVATE | PLATFORM_MAP_ANONYMOUS,
102 anonymous_fd,
103 offset));
104
105 #ifdef CVMFS_SUPPRESS_ASSERTS
106 } while (mem == MAP_FAILED);
107 #endif
108 // printf("SMMAP %d bytes at %p\n", pages*4096, mem);
109 // NOLINTNEXTLINE(performance-no-int-to-ptr)
110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 144024 times.
144024 assert((mem != MAP_FAILED) && "Out Of Memory");
111 144024 *(reinterpret_cast<size_t *>(mem)) = kMemMarker;
112 144024 *(reinterpret_cast<size_t *>(mem) + 1) = pages;
113 144024 return mem + 2 * sizeof(size_t);
114 }
115
116 143722 static inline void __attribute__((used)) smunmap(void *mem) {
117 143722 unsigned char *area = static_cast<unsigned char *>(mem);
118 143722 area = area - sizeof(size_t);
119 143722 const size_t pages = *(reinterpret_cast<size_t *>(area));
120 143722 const int retval = munmap(area - sizeof(size_t), pages * 4096);
121 // printf("SUNMMAP %d bytes at %p\n", pages*4096, area);
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 143722 times.
143722 assert((retval == 0) && "Invalid umnmap");
123 143722 }
124
125
126 /**
127 * Used when the caller remembers the size, so that it can call sxunmap later.
128 */
129 14302 static inline void * __attribute__((used)) sxmmap(size_t size) {
130 14302 const int anonymous_fd = -1;
131 14302 const off_t offset = 0;
132 14302 void *mem = NULL;
133
134 #ifdef CVMFS_SUPPRESS_ASSERTS
135 do {
136 #endif
137 14302 mem = mmap(NULL,
138 size,
139 PROT_READ | PROT_WRITE,
140 MAP_PRIVATE | PLATFORM_MAP_ANONYMOUS,
141 anonymous_fd,
142 offset);
143
144 #ifdef CVMFS_SUPPRESS_ASSERTS
145 } while (mem == MAP_FAILED);
146 #endif
147 // NOLINTNEXTLINE(performance-no-int-to-ptr)
148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14302 times.
14302 assert((mem != MAP_FAILED) && "Out Of Memory");
149 14302 return mem;
150 }
151
152
153 /**
154 * Free memory acquired by sxmmap.
155 */
156 36989 static inline void __attribute__((used)) sxunmap(void *mem, size_t size) {
157 36989 const int retval = munmap(mem, size);
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36989 times.
36989 assert((retval == 0) && "Invalid umnmap");
159 36989 }
160
161
162 /**
163 * Pointer is aligned at a multiple of the size. The size has to be a multiple
164 * of 2MB.
165 */
166 11436 static inline void * __attribute__((used)) sxmmap_align(size_t size) {
167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11436 times.
11436 assert((size % (2 * 1024 * 1024)) == 0);
168 11436 char *mem = NULL;
169 #ifdef CVMFS_SUPPRESS_ASSERTS
170 do {
171 #endif
172 11436 mem = reinterpret_cast<char *>(sxmmap(2 * size));
173 #ifdef CVMFS_SUPPRESS_ASSERTS
174 } while (mem == MAP_FAILED);
175 #endif
176
177 11436 const uintptr_t head = size - (uintptr_t(mem) % size);
178 11436 sxunmap(mem, head);
179 11436 mem += head;
180 11436 const uintptr_t tail = size - head;
181
2/2
✓ Branch 0 taken 11265 times.
✓ Branch 1 taken 171 times.
11436 if (tail > 0)
182 11265 sxunmap(mem + size, tail);
183 11436 return mem;
184 }
185
186
187 #ifdef CVMFS_NAMESPACE_GUARD
188 } // namespace CVMFS_NAMESPACE_GUARD
189 #endif
190
191 #endif // CVMFS_UTIL_SMALLOC_H_
192