• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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