Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/loader/aot_section.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "loader/aot_section.h"
5
#include "common/spdlog.h"
6
#include "system/allocator.h"
7
8
#if WASMEDGE_OS_LINUX || WASMEDGE_OS_MACOS
9
extern "C" {
10
extern void __register_frame(void *);
11
extern void __deregister_frame(void *);
12
}
13
#endif
14
15
using namespace std::literals;
16
17
namespace {
18
0
inline constexpr uint64_t roundDownPageBoundary(const uint64_t Value) {
19
// ARM64 Mac has a special page size
20
#if WASMEDGE_OS_MACOS && defined(__aarch64__)
21
  return Value & ~UINT64_C(16383);
22
#else
23
0
  return Value & ~UINT64_C(4095);
24
0
#endif
25
0
}
26
0
inline constexpr uint64_t roundUpPageBoundary(const uint64_t Value) {
27
// ARM64 Mac has a special page size
28
#if WASMEDGE_OS_MACOS && defined(__aarch64__)
29
  return roundDownPageBoundary(Value + UINT64_C(16383));
30
#else
31
0
  return roundDownPageBoundary(Value + UINT64_C(4095));
32
0
#endif
33
0
}
34
} // namespace
35
36
namespace WasmEdge::Loader {
37
38
0
Expect<void> AOTSection::load(const AST::AOTSection &AOTSec) noexcept {
39
0
  BinarySize = 0;
40
0
  for (const auto &Section : AOTSec.getSections()) {
41
0
    const auto Offset = std::get<1>(Section);
42
0
    const auto Size = std::get<2>(Section);
43
0
    BinarySize = std::max(BinarySize, Offset + Size);
44
0
  }
45
0
  BinarySize = roundUpPageBoundary(BinarySize);
46
47
  // The symbol addresses are offsets into the binary about to be mapped, and
48
  // are dereferenced without any further check, so reject the out-of-range
49
  // ones here.
50
0
  if (!checkAccessBound(AOTSec.getIntrinsicsAddress(),
51
0
                        sizeof(const IntrinsicsTable *))) {
52
0
    spdlog::error(ErrCode::Value::IntegerTooLarge);
53
0
    spdlog::error("    AOT intrinsics address out of range."sv);
54
0
    return Unexpect(ErrCode::Value::IntegerTooLarge);
55
0
  }
56
0
  for (const auto Address : AOTSec.getTypesAddress()) {
57
0
    if (!checkAccessBound(Address, 1)) {
58
0
      spdlog::error(ErrCode::Value::IntegerTooLarge);
59
0
      spdlog::error("    AOT type address out of range."sv);
60
0
      return Unexpect(ErrCode::Value::IntegerTooLarge);
61
0
    }
62
0
  }
63
0
  for (const auto Address : AOTSec.getCodesAddress()) {
64
0
    if (!checkAccessBound(Address, 1)) {
65
0
      spdlog::error(ErrCode::Value::IntegerTooLarge);
66
0
      spdlog::error("    AOT code address out of range."sv);
67
0
      return Unexpect(ErrCode::Value::IntegerTooLarge);
68
0
    }
69
0
  }
70
71
0
  Binary = Allocator::allocate_chunk(BinarySize);
72
0
  if (unlikely(!Binary)) {
73
0
    spdlog::error(ErrCode::Value::MemoryOutOfBounds);
74
0
    return Unexpect(ErrCode::Value::MemoryOutOfBounds);
75
0
  }
76
77
0
  std::vector<std::pair<uint8_t *, uint64_t>> ExecutableRanges;
78
0
  for (const auto &Section : AOTSec.getSections()) {
79
0
    const auto Offset = std::get<1>(Section);
80
0
    const auto Size = std::get<2>(Section);
81
0
    const auto &Content = std::get<3>(Section);
82
0
    if (Size > BinarySize || Offset > BinarySize ||
83
0
        Offset + Size > BinarySize || Content.size() > Size) {
84
0
      return Unexpect(ErrCode::Value::IntegerTooLarge);
85
0
    }
86
0
    std::copy(Content.begin(), Content.end(), Binary + Offset);
87
0
    switch (std::get<0>(Section)) {
88
0
    case 1: { // Text
89
0
      const auto O = roundDownPageBoundary(Offset);
90
0
      const auto S = roundUpPageBoundary(Size + (Offset - O));
91
0
      ExecutableRanges.emplace_back(Binary + O, S);
92
0
      break;
93
0
    }
94
0
    case 2: // Data
95
0
      break;
96
0
    case 3: // BSS
97
0
      break;
98
0
#if WASMEDGE_OS_LINUX
99
0
    case 4: // EHFrame
100
0
      EHFrameAddress = reinterpret_cast<void *>(Binary + Offset);
101
0
      break;
102
#elif WASMEDGE_OS_MACOS
103
    case 4: // EHFrame
104
      EHFrameAddress = reinterpret_cast<uint8_t *>(Binary + Offset);
105
      EHFrameSize = Size;
106
      break;
107
#elif WASMEDGE_OS_WINDOWS
108
    case 4: // PData
109
      PDataAddress = reinterpret_cast<void *>(Binary + Offset);
110
      PDataSize =
111
          static_cast<uint32_t>(Size / sizeof(winapi::RUNTIME_FUNCTION_));
112
      break;
113
#endif
114
0
    default:
115
0
      return Unexpect(ErrCode::Value::IntegerTooLarge);
116
0
    }
117
0
  }
118
119
0
  for (const auto &[Pointer, Size] : ExecutableRanges) {
120
0
    if (!Allocator::set_chunk_executable(Pointer, Size)) {
121
0
      spdlog::error(ErrCode::Value::MemoryOutOfBounds);
122
0
      spdlog::error("    set_chunk_executable failed:{}"sv,
123
0
                    std::strerror(errno));
124
0
      return Unexpect(ErrCode::Value::MemoryOutOfBounds);
125
0
    }
126
0
  }
127
128
0
  IntrinsicsAddress = AOTSec.getIntrinsicsAddress();
129
0
  TypesAddress = AOTSec.getTypesAddress();
130
0
  CodesAddress = AOTSec.getCodesAddress();
131
132
0
#if WASMEDGE_OS_LINUX
133
0
  if (EHFrameAddress) {
134
0
    __register_frame(EHFrameAddress);
135
0
  }
136
#elif WASMEDGE_OS_MACOS
137
  if (EHFrameAddress) {
138
    auto Iter = EHFrameAddress;
139
    const auto End = EHFrameAddress + EHFrameSize - 4;
140
141
    while (Iter < End) {
142
      if (Iter != EHFrameAddress) {
143
        __register_frame(Iter);
144
      }
145
      const uint32_t Length = *reinterpret_cast<const uint32_t *>(Iter);
146
      Iter += Length + 4;
147
    }
148
  }
149
#elif WASMEDGE_OS_WINDOWS
150
  if (PDataSize != 0) {
151
    winapi::RtlAddFunctionTable(
152
        static_cast<winapi::PRUNTIME_FUNCTION_>(PDataAddress), PDataSize,
153
        reinterpret_cast<winapi::ULONG_PTR_>(Binary));
154
  }
155
#endif
156
157
0
  return {};
158
0
}
159
160
0
void AOTSection::unload() noexcept {
161
0
  if (Binary) {
162
0
#if WASMEDGE_OS_LINUX
163
0
    if (EHFrameAddress) {
164
0
      __deregister_frame(EHFrameAddress);
165
0
    }
166
#elif WASMEDGE_OS_MACOS
167
    if (EHFrameAddress) {
168
      auto Iter = EHFrameAddress;
169
      const auto End = EHFrameAddress + EHFrameSize - 4;
170
171
      while (Iter < End) {
172
        if (Iter != EHFrameAddress) {
173
          __deregister_frame(Iter);
174
        }
175
        const uint32_t Length = *reinterpret_cast<const uint32_t *>(Iter);
176
        Iter += Length + 4;
177
      }
178
    }
179
#elif WASMEDGE_OS_WINDOWS
180
    if (PDataSize != 0) {
181
      winapi::RtlDeleteFunctionTable(
182
          static_cast<winapi::PRUNTIME_FUNCTION_>(PDataAddress));
183
    }
184
#endif
185
0
    Allocator::set_chunk_readable_writable(Binary, BinarySize);
186
0
    Allocator::release_chunk(Binary, BinarySize);
187
0
    Binary = nullptr;
188
0
  }
189
0
}
190
191
} // namespace WasmEdge::Loader