1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <math.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8
9 #include <limits>
10
11 #include "include/v8config.h"
12 #include "src/base/bits.h"
13 #include "src/base/ieee754.h"
14 #include "src/base/safe_conversions.h"
15 #include "src/common/assert-scope.h"
16 #include "src/utils/memcopy.h"
17 #include "src/wasm/wasm-objects-inl.h"
18
19 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
20 defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) || \
21 defined(UNDEFINED_SANITIZER)
22 #define V8_WITH_SANITIZER
23 #endif
24
25 #if defined(V8_OS_WIN) && defined(V8_WITH_SANITIZER)
26 // With ASAN on Windows we have to reset the thread-in-wasm flag. Exceptions
27 // caused by ASAN let the thread-in-wasm flag get out of sync. Even marking
28 // functions with DISABLE_ASAN is not sufficient when the compiler produces
29 // calls to memset. Therefore we add test-specific code for ASAN on
30 // Windows.
31 #define RESET_THREAD_IN_WASM_FLAG_FOR_ASAN_ON_WINDOWS
32 #include "src/trap-handler/trap-handler.h"
33 #endif
34
35 #include "src/base/memory.h"
36 #include "src/utils/utils.h"
37 #include "src/wasm/wasm-external-refs.h"
38
39 namespace v8 {
40 namespace internal {
41 namespace wasm {
42
43 using base::ReadUnalignedValue;
44 using base::WriteUnalignedValue;
45
f32_trunc_wrapper(Address data)46 void f32_trunc_wrapper(Address data) {
47 WriteUnalignedValue<float>(data, truncf(ReadUnalignedValue<float>(data)));
48 }
49
f32_floor_wrapper(Address data)50 void f32_floor_wrapper(Address data) {
51 WriteUnalignedValue<float>(data, floorf(ReadUnalignedValue<float>(data)));
52 }
53
f32_ceil_wrapper(Address data)54 void f32_ceil_wrapper(Address data) {
55 WriteUnalignedValue<float>(data, ceilf(ReadUnalignedValue<float>(data)));
56 }
57
f32_nearest_int_wrapper(Address data)58 void f32_nearest_int_wrapper(Address data) {
59 WriteUnalignedValue<float>(data, nearbyintf(ReadUnalignedValue<float>(data)));
60 }
61
f64_trunc_wrapper(Address data)62 void f64_trunc_wrapper(Address data) {
63 WriteUnalignedValue<double>(data, trunc(ReadUnalignedValue<double>(data)));
64 }
65
f64_floor_wrapper(Address data)66 void f64_floor_wrapper(Address data) {
67 WriteUnalignedValue<double>(data, floor(ReadUnalignedValue<double>(data)));
68 }
69
f64_ceil_wrapper(Address data)70 void f64_ceil_wrapper(Address data) {
71 WriteUnalignedValue<double>(data, ceil(ReadUnalignedValue<double>(data)));
72 }
73
f64_nearest_int_wrapper(Address data)74 void f64_nearest_int_wrapper(Address data) {
75 WriteUnalignedValue<double>(data,
76 nearbyint(ReadUnalignedValue<double>(data)));
77 }
78
int64_to_float32_wrapper(Address data)79 void int64_to_float32_wrapper(Address data) {
80 int64_t input = ReadUnalignedValue<int64_t>(data);
81 WriteUnalignedValue<float>(data, static_cast<float>(input));
82 }
83
uint64_to_float32_wrapper(Address data)84 void uint64_to_float32_wrapper(Address data) {
85 uint64_t input = ReadUnalignedValue<uint64_t>(data);
86 #if defined(V8_OS_WIN)
87 // On Windows, the FP stack registers calculate with less precision, which
88 // leads to a uint64_t to float32 conversion which does not satisfy the
89 // WebAssembly specification. Therefore we do a different approach here:
90 //
91 // / leading 0 \/ 24 float data bits \/ for rounding \/ trailing 0 \
92 // 00000000000001XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX100000000000000
93 //
94 // Float32 can only represent 24 data bit (1 implicit 1 bit + 23 mantissa
95 // bits). Starting from the most significant 1 bit, we can therefore extract
96 // 24 bits and do the conversion only on them. The other bits can affect the
97 // result only through rounding. Rounding works as follows:
98 // * If the most significant rounding bit is not set, then round down.
99 // * If the most significant rounding bit is set, and at least one of the
100 // other rounding bits is set, then round up.
101 // * If the most significant rounding bit is set, but all other rounding bits
102 // are not set, then round to even.
103 // We can aggregate 'all other rounding bits' in the second-most significant
104 // rounding bit.
105 // The resulting algorithm is therefore as follows:
106 // * Check if the distance between the most significant bit (MSB) and the
107 // least significant bit (LSB) is greater than 25 bits. If the distance is
108 // less or equal to 25 bits, the uint64 to float32 conversion is anyways
109 // exact, and we just use the C++ conversion.
110 // * Find the most significant bit (MSB).
111 // * Starting from the MSB, extract 25 bits (24 data bits + the first rounding
112 // bit).
113 // * The remaining rounding bits are guaranteed to contain at least one 1 bit,
114 // due to the check we did above.
115 // * Store the 25 bits + 1 aggregated bit in an uint32_t.
116 // * Convert this uint32_t to float. The conversion does the correct rounding
117 // now.
118 // * Shift the result back to the original magnitude.
119 uint32_t leading_zeros = base::bits::CountLeadingZeros(input);
120 uint32_t trailing_zeros = base::bits::CountTrailingZeros(input);
121 constexpr uint32_t num_extracted_bits = 25;
122 // Check if there are any rounding bits we have to aggregate.
123 if (leading_zeros + trailing_zeros + num_extracted_bits < 64) {
124 // Shift to extract the data bits.
125 uint32_t num_aggregation_bits = 64 - num_extracted_bits - leading_zeros;
126 // We extract the bits we want to convert. Note that we convert one bit more
127 // than necessary. This bit is a placeholder where we will store the
128 // aggregation bit.
129 int32_t extracted_bits =
130 static_cast<int32_t>(input >> (num_aggregation_bits - 1));
131 // Set the aggregation bit. We don't have to clear the slot first, because
132 // the bit there is also part of the aggregation.
133 extracted_bits |= 1;
134 float result = static_cast<float>(extracted_bits);
135 // We have to shift the result back. The shift amount is
136 // (num_aggregation_bits - 1), which is the shift amount we did originally,
137 // and (-2), which is for the two additional bits we kept originally for
138 // rounding.
139 int32_t shift_back = static_cast<int32_t>(num_aggregation_bits) - 1 - 2;
140 // Calculate the multiplier to shift the extracted bits back to the original
141 // magnitude. This multiplier is a power of two, so in the float32 bit
142 // representation we just have to construct the correct exponent and put it
143 // at the correct bit offset. The exponent consists of 8 bits, starting at
144 // the second MSB (a.k.a '<< 23'). The encoded exponent itself is
145 // ('actual exponent' - 127).
146 int32_t multiplier_bits = ((shift_back - 127) & 0xff) << 23;
147 result *= bit_cast<float>(multiplier_bits);
148 WriteUnalignedValue<float>(data, result);
149 return;
150 }
151 #endif // defined(V8_OS_WIN)
152 WriteUnalignedValue<float>(data, static_cast<float>(input));
153 }
154
int64_to_float64_wrapper(Address data)155 void int64_to_float64_wrapper(Address data) {
156 int64_t input = ReadUnalignedValue<int64_t>(data);
157 WriteUnalignedValue<double>(data, static_cast<double>(input));
158 }
159
uint64_to_float64_wrapper(Address data)160 void uint64_to_float64_wrapper(Address data) {
161 uint64_t input = ReadUnalignedValue<uint64_t>(data);
162 double result = static_cast<double>(input);
163
164 #if V8_CC_MSVC
165 // With MSVC we use static_cast<double>(uint32_t) instead of
166 // static_cast<double>(uint64_t) to achieve round-to-nearest-ties-even
167 // semantics. The idea is to calculate
168 // static_cast<double>(high_word) * 2^32 + static_cast<double>(low_word).
169 uint32_t low_word = static_cast<uint32_t>(input & 0xFFFFFFFF);
170 uint32_t high_word = static_cast<uint32_t>(input >> 32);
171
172 double shift = static_cast<double>(1ull << 32);
173
174 result = static_cast<double>(high_word);
175 result *= shift;
176 result += static_cast<double>(low_word);
177 #endif
178
179 WriteUnalignedValue<double>(data, result);
180 }
181
float32_to_int64_wrapper(Address data)182 int32_t float32_to_int64_wrapper(Address data) {
183 float input = ReadUnalignedValue<float>(data);
184 if (base::IsValueInRangeForNumericType<int64_t>(input)) {
185 WriteUnalignedValue<int64_t>(data, static_cast<int64_t>(input));
186 return 1;
187 }
188 return 0;
189 }
190
float32_to_uint64_wrapper(Address data)191 int32_t float32_to_uint64_wrapper(Address data) {
192 float input = ReadUnalignedValue<float>(data);
193 if (base::IsValueInRangeForNumericType<uint64_t>(input)) {
194 WriteUnalignedValue<uint64_t>(data, static_cast<uint64_t>(input));
195 return 1;
196 }
197 return 0;
198 }
199
float64_to_int64_wrapper(Address data)200 int32_t float64_to_int64_wrapper(Address data) {
201 double input = ReadUnalignedValue<double>(data);
202 if (base::IsValueInRangeForNumericType<int64_t>(input)) {
203 WriteUnalignedValue<int64_t>(data, static_cast<int64_t>(input));
204 return 1;
205 }
206 return 0;
207 }
208
float64_to_uint64_wrapper(Address data)209 int32_t float64_to_uint64_wrapper(Address data) {
210 double input = ReadUnalignedValue<double>(data);
211 if (base::IsValueInRangeForNumericType<uint64_t>(input)) {
212 WriteUnalignedValue<uint64_t>(data, static_cast<uint64_t>(input));
213 return 1;
214 }
215 return 0;
216 }
217
float32_to_int64_sat_wrapper(Address data)218 void float32_to_int64_sat_wrapper(Address data) {
219 float input = ReadUnalignedValue<float>(data);
220 if (base::IsValueInRangeForNumericType<int64_t>(input)) {
221 WriteUnalignedValue<int64_t>(data, static_cast<int64_t>(input));
222 return;
223 }
224 if (std::isnan(input)) {
225 WriteUnalignedValue<int64_t>(data, 0);
226 return;
227 }
228 if (input < 0.0) {
229 WriteUnalignedValue<int64_t>(data, std::numeric_limits<int64_t>::min());
230 return;
231 }
232 WriteUnalignedValue<int64_t>(data, std::numeric_limits<int64_t>::max());
233 }
234
float32_to_uint64_sat_wrapper(Address data)235 void float32_to_uint64_sat_wrapper(Address data) {
236 float input = ReadUnalignedValue<float>(data);
237 if (base::IsValueInRangeForNumericType<uint64_t>(input)) {
238 WriteUnalignedValue<uint64_t>(data, static_cast<uint64_t>(input));
239 return;
240 }
241 if (input >= std::numeric_limits<uint64_t>::max()) {
242 WriteUnalignedValue<uint64_t>(data, std::numeric_limits<uint64_t>::max());
243 return;
244 }
245 WriteUnalignedValue<uint64_t>(data, 0);
246 }
247
float64_to_int64_sat_wrapper(Address data)248 void float64_to_int64_sat_wrapper(Address data) {
249 double input = ReadUnalignedValue<double>(data);
250 if (base::IsValueInRangeForNumericType<int64_t>(input)) {
251 WriteUnalignedValue<int64_t>(data, static_cast<int64_t>(input));
252 return;
253 }
254 if (std::isnan(input)) {
255 WriteUnalignedValue<int64_t>(data, 0);
256 return;
257 }
258 if (input < 0.0) {
259 WriteUnalignedValue<int64_t>(data, std::numeric_limits<int64_t>::min());
260 return;
261 }
262 WriteUnalignedValue<int64_t>(data, std::numeric_limits<int64_t>::max());
263 }
264
float64_to_uint64_sat_wrapper(Address data)265 void float64_to_uint64_sat_wrapper(Address data) {
266 double input = ReadUnalignedValue<double>(data);
267 if (base::IsValueInRangeForNumericType<uint64_t>(input)) {
268 WriteUnalignedValue<uint64_t>(data, static_cast<uint64_t>(input));
269 return;
270 }
271 if (input >= std::numeric_limits<uint64_t>::max()) {
272 WriteUnalignedValue<uint64_t>(data, std::numeric_limits<uint64_t>::max());
273 return;
274 }
275 WriteUnalignedValue<uint64_t>(data, 0);
276 }
277
int64_div_wrapper(Address data)278 int32_t int64_div_wrapper(Address data) {
279 int64_t dividend = ReadUnalignedValue<int64_t>(data);
280 int64_t divisor = ReadUnalignedValue<int64_t>(data + sizeof(dividend));
281 if (divisor == 0) {
282 return 0;
283 }
284 if (divisor == -1 && dividend == std::numeric_limits<int64_t>::min()) {
285 return -1;
286 }
287 WriteUnalignedValue<int64_t>(data, dividend / divisor);
288 return 1;
289 }
290
int64_mod_wrapper(Address data)291 int32_t int64_mod_wrapper(Address data) {
292 int64_t dividend = ReadUnalignedValue<int64_t>(data);
293 int64_t divisor = ReadUnalignedValue<int64_t>(data + sizeof(dividend));
294 if (divisor == 0) {
295 return 0;
296 }
297 if (divisor == -1 && dividend == std::numeric_limits<int64_t>::min()) {
298 WriteUnalignedValue<int64_t>(data, 0);
299 return 1;
300 }
301 WriteUnalignedValue<int64_t>(data, dividend % divisor);
302 return 1;
303 }
304
uint64_div_wrapper(Address data)305 int32_t uint64_div_wrapper(Address data) {
306 uint64_t dividend = ReadUnalignedValue<uint64_t>(data);
307 uint64_t divisor = ReadUnalignedValue<uint64_t>(data + sizeof(dividend));
308 if (divisor == 0) {
309 return 0;
310 }
311 WriteUnalignedValue<uint64_t>(data, dividend / divisor);
312 return 1;
313 }
314
uint64_mod_wrapper(Address data)315 int32_t uint64_mod_wrapper(Address data) {
316 uint64_t dividend = ReadUnalignedValue<uint64_t>(data);
317 uint64_t divisor = ReadUnalignedValue<uint64_t>(data + sizeof(dividend));
318 if (divisor == 0) {
319 return 0;
320 }
321 WriteUnalignedValue<uint64_t>(data, dividend % divisor);
322 return 1;
323 }
324
word32_ctz_wrapper(Address data)325 uint32_t word32_ctz_wrapper(Address data) {
326 return base::bits::CountTrailingZeros(ReadUnalignedValue<uint32_t>(data));
327 }
328
word64_ctz_wrapper(Address data)329 uint32_t word64_ctz_wrapper(Address data) {
330 return base::bits::CountTrailingZeros(ReadUnalignedValue<uint64_t>(data));
331 }
332
word32_popcnt_wrapper(Address data)333 uint32_t word32_popcnt_wrapper(Address data) {
334 return base::bits::CountPopulation(ReadUnalignedValue<uint32_t>(data));
335 }
336
word64_popcnt_wrapper(Address data)337 uint32_t word64_popcnt_wrapper(Address data) {
338 return base::bits::CountPopulation(ReadUnalignedValue<uint64_t>(data));
339 }
340
word32_rol_wrapper(Address data)341 uint32_t word32_rol_wrapper(Address data) {
342 uint32_t input = ReadUnalignedValue<uint32_t>(data);
343 uint32_t shift = ReadUnalignedValue<uint32_t>(data + sizeof(input)) & 31;
344 return (input << shift) | (input >> ((32 - shift) & 31));
345 }
346
word32_ror_wrapper(Address data)347 uint32_t word32_ror_wrapper(Address data) {
348 uint32_t input = ReadUnalignedValue<uint32_t>(data);
349 uint32_t shift = ReadUnalignedValue<uint32_t>(data + sizeof(input)) & 31;
350 return (input >> shift) | (input << ((32 - shift) & 31));
351 }
352
word64_rol_wrapper(Address data)353 void word64_rol_wrapper(Address data) {
354 uint64_t input = ReadUnalignedValue<uint64_t>(data);
355 uint64_t shift = ReadUnalignedValue<uint64_t>(data + sizeof(input)) & 63;
356 uint64_t result = (input << shift) | (input >> ((64 - shift) & 63));
357 WriteUnalignedValue<uint64_t>(data, result);
358 }
359
word64_ror_wrapper(Address data)360 void word64_ror_wrapper(Address data) {
361 uint64_t input = ReadUnalignedValue<uint64_t>(data);
362 uint64_t shift = ReadUnalignedValue<uint64_t>(data + sizeof(input)) & 63;
363 uint64_t result = (input >> shift) | (input << ((64 - shift) & 63));
364 WriteUnalignedValue<uint64_t>(data, result);
365 }
366
float64_pow_wrapper(Address data)367 void float64_pow_wrapper(Address data) {
368 double x = ReadUnalignedValue<double>(data);
369 double y = ReadUnalignedValue<double>(data + sizeof(x));
370 WriteUnalignedValue<double>(data, base::ieee754::pow(x, y));
371 }
372
373 template <typename T, T (*float_round_op)(T)>
simd_float_round_wrapper(Address data)374 void simd_float_round_wrapper(Address data) {
375 constexpr int n = kSimd128Size / sizeof(T);
376 for (int i = 0; i < n; i++) {
377 T input = ReadUnalignedValue<T>(data + (i * sizeof(T)));
378 T value = float_round_op(input);
379 #if V8_OS_AIX
380 value = FpOpWorkaround<T>(input, value);
381 #endif
382 WriteUnalignedValue<T>(data + (i * sizeof(T)), value);
383 }
384 }
385
f64x2_ceil_wrapper(Address data)386 void f64x2_ceil_wrapper(Address data) {
387 simd_float_round_wrapper<double, &ceil>(data);
388 }
389
f64x2_floor_wrapper(Address data)390 void f64x2_floor_wrapper(Address data) {
391 simd_float_round_wrapper<double, &floor>(data);
392 }
393
f64x2_trunc_wrapper(Address data)394 void f64x2_trunc_wrapper(Address data) {
395 simd_float_round_wrapper<double, &trunc>(data);
396 }
397
f64x2_nearest_int_wrapper(Address data)398 void f64x2_nearest_int_wrapper(Address data) {
399 simd_float_round_wrapper<double, &nearbyint>(data);
400 }
401
f32x4_ceil_wrapper(Address data)402 void f32x4_ceil_wrapper(Address data) {
403 simd_float_round_wrapper<float, &ceilf>(data);
404 }
405
f32x4_floor_wrapper(Address data)406 void f32x4_floor_wrapper(Address data) {
407 simd_float_round_wrapper<float, &floorf>(data);
408 }
409
f32x4_trunc_wrapper(Address data)410 void f32x4_trunc_wrapper(Address data) {
411 simd_float_round_wrapper<float, &truncf>(data);
412 }
413
f32x4_nearest_int_wrapper(Address data)414 void f32x4_nearest_int_wrapper(Address data) {
415 simd_float_round_wrapper<float, &nearbyintf>(data);
416 }
417
418 namespace {
419 class ThreadNotInWasmScope {
420 // Asan on Windows triggers exceptions to allocate shadow memory lazily. When
421 // this function is called from WebAssembly, these exceptions would be handled
422 // by the trap handler before they get handled by Asan, and thereby confuse the
423 // thread-in-wasm flag. Therefore we disable ASAN for this function.
424 // Alternatively we could reset the thread-in-wasm flag before calling this
425 // function. However, as this is only a problem with Asan on Windows, we did not
426 // consider it worth the overhead.
427 #if defined(RESET_THREAD_IN_WASM_FLAG_FOR_ASAN_ON_WINDOWS)
428
429 public:
ThreadNotInWasmScope()430 ThreadNotInWasmScope() : thread_was_in_wasm_(trap_handler::IsThreadInWasm()) {
431 if (thread_was_in_wasm_) {
432 trap_handler::ClearThreadInWasm();
433 }
434 }
435
~ThreadNotInWasmScope()436 ~ThreadNotInWasmScope() {
437 if (thread_was_in_wasm_) {
438 trap_handler::SetThreadInWasm();
439 }
440 }
441
442 private:
443 bool thread_was_in_wasm_;
444 #else
445
446 public:
447 ThreadNotInWasmScope() {
448 // This is needed to avoid compilation errors (unused variable).
449 USE(this);
450 }
451 #endif
452 };
453
454 #ifdef DISABLE_UNTRUSTED_CODE_MITIGATIONS
EffectiveAddress(WasmInstanceObject instance,uint32_t index)455 inline byte* EffectiveAddress(WasmInstanceObject instance, uint32_t index) {
456 return instance.memory_start() + index;
457 }
458
EffectiveAddress(byte * base,size_t size,uint32_t index)459 inline byte* EffectiveAddress(byte* base, size_t size, uint32_t index) {
460 return base + index;
461 }
462
463 #else
EffectiveAddress(WasmInstanceObject instance,uint32_t index)464 inline byte* EffectiveAddress(WasmInstanceObject instance, uint32_t index) {
465 // Compute the effective address of the access, making sure to condition
466 // the index even in the in-bounds case.
467 return instance.memory_start() + (index & instance.memory_mask());
468 }
469
EffectiveAddress(byte * base,size_t size,uint32_t index)470 inline byte* EffectiveAddress(byte* base, size_t size, uint32_t index) {
471 size_t mem_mask = base::bits::RoundUpToPowerOfTwo(size) - 1;
472 return base + (index & mem_mask);
473 }
474 #endif
475
476 template <typename V>
ReadAndIncrementOffset(Address data,size_t * offset)477 V ReadAndIncrementOffset(Address data, size_t* offset) {
478 V result = ReadUnalignedValue<V>(data + *offset);
479 *offset += sizeof(V);
480 return result;
481 }
482 } // namespace
483
memory_init_wrapper(Address data)484 int32_t memory_init_wrapper(Address data) {
485 constexpr int32_t kSuccess = 1;
486 constexpr int32_t kOutOfBounds = 0;
487 ThreadNotInWasmScope thread_not_in_wasm_scope;
488 DisallowHeapAllocation disallow_heap_allocation;
489 size_t offset = 0;
490 Object raw_instance = ReadAndIncrementOffset<Object>(data, &offset);
491 WasmInstanceObject instance = WasmInstanceObject::cast(raw_instance);
492 uint32_t dst = ReadAndIncrementOffset<uint32_t>(data, &offset);
493 uint32_t src = ReadAndIncrementOffset<uint32_t>(data, &offset);
494 uint32_t seg_index = ReadAndIncrementOffset<uint32_t>(data, &offset);
495 uint32_t size = ReadAndIncrementOffset<uint32_t>(data, &offset);
496
497 uint64_t mem_size = instance.memory_size();
498 if (!base::IsInBounds<uint64_t>(dst, size, mem_size)) return kOutOfBounds;
499
500 uint32_t seg_size = instance.data_segment_sizes()[seg_index];
501 if (!base::IsInBounds<uint32_t>(src, size, seg_size)) return kOutOfBounds;
502
503 byte* seg_start =
504 reinterpret_cast<byte*>(instance.data_segment_starts()[seg_index]);
505 std::memcpy(EffectiveAddress(instance, dst),
506 EffectiveAddress(seg_start, seg_size, src), size);
507 return kSuccess;
508 }
509
memory_copy_wrapper(Address data)510 int32_t memory_copy_wrapper(Address data) {
511 constexpr int32_t kSuccess = 1;
512 constexpr int32_t kOutOfBounds = 0;
513 ThreadNotInWasmScope thread_not_in_wasm_scope;
514 DisallowHeapAllocation disallow_heap_allocation;
515 size_t offset = 0;
516 Object raw_instance = ReadAndIncrementOffset<Object>(data, &offset);
517 WasmInstanceObject instance = WasmInstanceObject::cast(raw_instance);
518 uint32_t dst = ReadAndIncrementOffset<uint32_t>(data, &offset);
519 uint32_t src = ReadAndIncrementOffset<uint32_t>(data, &offset);
520 uint32_t size = ReadAndIncrementOffset<uint32_t>(data, &offset);
521
522 uint64_t mem_size = instance.memory_size();
523 if (!base::IsInBounds<uint64_t>(dst, size, mem_size)) return kOutOfBounds;
524 if (!base::IsInBounds<uint64_t>(src, size, mem_size)) return kOutOfBounds;
525
526 // Use std::memmove, because the ranges can overlap.
527 std::memmove(EffectiveAddress(instance, dst), EffectiveAddress(instance, src),
528 size);
529 return kSuccess;
530 }
531
memory_fill_wrapper(Address data)532 int32_t memory_fill_wrapper(Address data) {
533 constexpr int32_t kSuccess = 1;
534 constexpr int32_t kOutOfBounds = 0;
535
536 ThreadNotInWasmScope thread_not_in_wasm_scope;
537 DisallowHeapAllocation disallow_heap_allocation;
538
539 size_t offset = 0;
540 Object raw_instance = ReadAndIncrementOffset<Object>(data, &offset);
541 WasmInstanceObject instance = WasmInstanceObject::cast(raw_instance);
542 uint32_t dst = ReadAndIncrementOffset<uint32_t>(data, &offset);
543 uint8_t value =
544 static_cast<uint8_t>(ReadAndIncrementOffset<uint32_t>(data, &offset));
545 uint32_t size = ReadAndIncrementOffset<uint32_t>(data, &offset);
546
547 uint64_t mem_size = instance.memory_size();
548 if (!base::IsInBounds<uint64_t>(dst, size, mem_size)) return kOutOfBounds;
549
550 std::memset(EffectiveAddress(instance, dst), value, size);
551 return kSuccess;
552 }
553
554 static WasmTrapCallbackForTesting wasm_trap_callback_for_testing = nullptr;
555
set_trap_callback_for_testing(WasmTrapCallbackForTesting callback)556 void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) {
557 wasm_trap_callback_for_testing = callback;
558 }
559
call_trap_callback_for_testing()560 void call_trap_callback_for_testing() {
561 if (wasm_trap_callback_for_testing) {
562 wasm_trap_callback_for_testing();
563 }
564 }
565
566 } // namespace wasm
567 } // namespace internal
568 } // namespace v8
569
570 #undef V8_WITH_SANITIZER
571 #undef RESET_THREAD_IN_WASM_FLAG_FOR_ASAN_ON_WINDOWS
572