Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/system/allocator.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "system/allocator.h"
5
6
#include "common/config.h"
7
#include "common/defines.h"
8
#include "common/errcode.h"
9
10
#if WASMEDGE_OS_WINDOWS
11
#include "system/winapi.h"
12
#elif defined(HAVE_MMAP) && defined(__x86_64__) || defined(__aarch64__) ||     \
13
    defined(__arm__) || (defined(__riscv) && __riscv_xlen == 64) ||            \
14
    defined(__s390x__)
15
#include <sys/mman.h>
16
#else
17
#include <cctype>
18
#include <cstdlib>
19
#include <cstring>
20
#endif
21
22
namespace WasmEdge {
23
24
namespace {
25
static inline constexpr const uint64_t kPageSize = UINT64_C(65536);
26
27
#if WASMEDGE_OS_WINDOWS || defined(HAVE_MMAP) && defined(__x86_64__) ||        \
28
    defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) ||        \
29
    defined(__s390x__)
30
// Only define these two constants on the supported platform to avoid
31
// -Wunused-const-variable error when applying -Werror.
32
static inline constexpr const uint64_t k4G = UINT64_C(0x100000000);
33
static inline constexpr const uint64_t k12G = UINT64_C(0x300000000);
34
#endif
35
36
} // namespace
37
38
0
WASMEDGE_EXPORT uint8_t *Allocator::allocate(uint64_t PageCount) noexcept {
39
#if WASMEDGE_OS_WINDOWS
40
  auto Reserved = reinterpret_cast<uint8_t *>(winapi::VirtualAlloc(
41
      nullptr, k12G, winapi::MEM_RESERVE_, winapi::PAGE_NOACCESS_));
42
  if (Reserved == nullptr) {
43
    return nullptr;
44
  }
45
  if (PageCount == 0) {
46
    return Reserved + k4G;
47
  }
48
  auto Pointer = resize(Reserved + k4G, 0, PageCount);
49
  if (Pointer == nullptr) {
50
    return nullptr;
51
  }
52
  return Pointer;
53
#elif defined(HAVE_MMAP) && defined(__x86_64__) || defined(__aarch64__) ||     \
54
    (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__)
55
  auto Reserved = reinterpret_cast<uint8_t *>(
56
0
      mmap(nullptr, k12G, PROT_NONE,
57
0
           MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0));
58
0
  if (Reserved == MAP_FAILED) {
59
0
    return nullptr;
60
0
  }
61
0
  if (PageCount == 0) {
62
0
    return Reserved + k4G;
63
0
  }
64
0
  auto Pointer = resize(Reserved + k4G, 0, PageCount);
65
0
  if (Pointer == nullptr) {
66
0
    return nullptr;
67
0
  }
68
0
  return Pointer;
69
#else
70
  auto Result = reinterpret_cast<uint8_t *>(std::malloc(kPageSize * PageCount));
71
  if (Result == nullptr) {
72
    return nullptr;
73
  }
74
  std::memset(Result, 0, kPageSize * PageCount);
75
  return Result;
76
#endif
77
0
}
78
79
WASMEDGE_EXPORT uint8_t *Allocator::resize(uint8_t *Pointer,
80
                                           uint64_t OldPageCount,
81
0
                                           uint64_t NewPageCount) noexcept {
82
0
  assuming(NewPageCount > OldPageCount);
83
#if WASMEDGE_OS_WINDOWS
84
  if (winapi::VirtualAlloc(Pointer + OldPageCount * kPageSize,
85
                           (NewPageCount - OldPageCount) * kPageSize,
86
                           winapi::MEM_COMMIT_,
87
                           winapi::PAGE_READWRITE_) == nullptr) {
88
    return nullptr;
89
  }
90
  return Pointer;
91
#elif defined(HAVE_MMAP) && (defined(__x86_64__) || defined(__aarch64__) ||    \
92
                             (defined(__riscv) && __riscv_xlen == 64)) ||      \
93
    defined(__s390x__)
94
0
  if (mmap(Pointer + OldPageCount * kPageSize,
95
0
           (NewPageCount - OldPageCount) * kPageSize, PROT_READ | PROT_WRITE,
96
0
           MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == MAP_FAILED) {
97
0
    return nullptr;
98
0
  }
99
0
  return Pointer;
100
#else
101
  auto Result = reinterpret_cast<uint8_t *>(
102
      std::realloc(Pointer, NewPageCount * kPageSize));
103
  if (Result == nullptr) {
104
    return nullptr;
105
  }
106
  std::memset(Result + OldPageCount * kPageSize, 0,
107
              (NewPageCount - OldPageCount) * kPageSize);
108
  return Result;
109
#endif
110
0
}
111
112
WASMEDGE_EXPORT uint8_t *Allocator::shrink(uint8_t *Pointer,
113
                                           uint64_t OldPageCount,
114
0
                                           uint64_t NewPageCount) noexcept {
115
0
  assuming(NewPageCount < OldPageCount);
116
#if WASMEDGE_OS_WINDOWS
117
  if (!winapi::VirtualFree(Pointer + NewPageCount * kPageSize,
118
                           (OldPageCount - NewPageCount) * kPageSize,
119
                           winapi::MEM_DECOMMIT_)) {
120
    return nullptr;
121
  }
122
  return Pointer;
123
#elif defined(HAVE_MMAP) && (defined(__x86_64__) || defined(__aarch64__) ||    \
124
                             (defined(__riscv) && __riscv_xlen == 64)) ||      \
125
    defined(__s390x__)
126
0
  if (mmap(Pointer + NewPageCount * kPageSize,
127
0
           (OldPageCount - NewPageCount) * kPageSize, PROT_NONE,
128
0
           MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_NORESERVE, -1,
129
0
           0) == MAP_FAILED) {
130
0
    return nullptr;
131
0
  }
132
0
  return Pointer;
133
#else
134
  return reinterpret_cast<uint8_t *>(
135
      std::realloc(Pointer, NewPageCount == 0 ? 1 : NewPageCount * kPageSize));
136
#endif
137
0
}
138
139
0
WASMEDGE_EXPORT void Allocator::release(uint8_t *Pointer, uint64_t) noexcept {
140
#if WASMEDGE_OS_WINDOWS
141
  winapi::VirtualFree(Pointer - k4G, 0, winapi::MEM_RELEASE_);
142
#elif defined(HAVE_MMAP) && (defined(__x86_64__) || defined(__aarch64__) ||    \
143
                             (defined(__riscv) && __riscv_xlen == 64)) ||      \
144
    defined(__s390x__)
145
0
  if (Pointer == nullptr) {
146
0
    return;
147
0
  }
148
0
  munmap(Pointer - k4G, k12G);
149
#else
150
  return std::free(Pointer);
151
#endif
152
0
}
153
154
0
uint8_t *Allocator::allocate_chunk(uint64_t Size) noexcept {
155
#if WASMEDGE_OS_WINDOWS
156
  if (auto Pointer = winapi::VirtualAlloc(nullptr, Size, winapi::MEM_COMMIT_,
157
                                          winapi::PAGE_READWRITE_);
158
      unlikely(Pointer == nullptr)) {
159
    return nullptr;
160
  } else {
161
    return reinterpret_cast<uint8_t *>(Pointer);
162
  }
163
#elif defined(HAVE_MMAP)
164
0
  if (auto Pointer = mmap(nullptr, Size, PROT_READ | PROT_WRITE,
165
0
                          MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
166
0
      unlikely(Pointer == MAP_FAILED)) {
167
0
    return nullptr;
168
0
  } else {
169
0
    return reinterpret_cast<uint8_t *>(Pointer);
170
0
  }
171
#else
172
  return std::malloc(Size);
173
#endif
174
0
}
175
176
void Allocator::release_chunk(uint8_t *Pointer,
177
0
                              uint64_t Size [[maybe_unused]]) noexcept {
178
#if WASMEDGE_OS_WINDOWS
179
  winapi::VirtualFree(Pointer, 0, winapi::MEM_RELEASE_);
180
#elif defined(HAVE_MMAP)
181
  munmap(Pointer, Size);
182
#else
183
  return std::free(Pointer);
184
#endif
185
0
}
186
187
0
bool Allocator::set_chunk_executable(uint8_t *Pointer, uint64_t Size) noexcept {
188
#if WASMEDGE_OS_WINDOWS
189
  winapi::DWORD_ OldPerm;
190
  return winapi::VirtualProtect(Pointer, Size, winapi::PAGE_EXECUTE_READ_,
191
                                &OldPerm) != 0;
192
#elif defined(HAVE_MMAP)
193
0
  return mprotect(Pointer, Size, PROT_EXEC | PROT_READ) == 0;
194
#else
195
  return true;
196
#endif
197
0
}
198
199
0
bool Allocator::set_chunk_readable(uint8_t *Pointer, uint64_t Size) noexcept {
200
#if WASMEDGE_OS_WINDOWS
201
  winapi::DWORD_ OldPerm;
202
  return winapi::VirtualProtect(Pointer, Size, winapi::PAGE_READONLY_,
203
                                &OldPerm) != 0;
204
#elif defined(HAVE_MMAP)
205
0
  return mprotect(Pointer, Size, PROT_READ) == 0;
206
#else
207
  return true;
208
#endif
209
0
}
210
211
bool Allocator::set_chunk_readable_writable(uint8_t *Pointer,
212
0
                                            uint64_t Size) noexcept {
213
#if WASMEDGE_OS_WINDOWS
214
  winapi::DWORD_ OldPerm;
215
  return winapi::VirtualProtect(Pointer, Size, winapi::PAGE_READWRITE_,
216
                                &OldPerm) != 0;
217
#elif defined(HAVE_MMAP)
218
0
  return mprotect(Pointer, Size, PROT_READ | PROT_WRITE) == 0;
219
#else
220
  return true;
221
#endif
222
0
}
223
224
} // namespace WasmEdge