+static void copyMemory(void* dst, const void* src, size_t size)
+{
+ size_t dstAsSize = reinterpret_cast<size_t>(dst);
+ size_t srcAsSize = reinterpret_cast<size_t>(src);
+ RELEASE_ASSERT(dstAsSize == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(dstAsSize));
+ RELEASE_ASSERT(srcAsSize == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(srcAsSize));
+ RELEASE_ASSERT(size == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(size));
+
+ intptr_t* dstPtr = reinterpret_cast<intptr_t*>(dst);
+ const intptr_t* srcPtr = reinterpret_cast<const intptr_t*>(src);
+ size /= sizeof(intptr_t);
+ while (size--)
+ *dstPtr++ = *srcPtr++;
+}
+
+
+
+// This function must not call malloc(), free(), or any other function that might
+// acquire a lock. Since 'thread' is suspended, trying to acquire a lock
+// will deadlock if 'thread' holds that lock.
+// This function, specifically the memory copying, was causing problems with Address Sanitizer in
+// apps. Since we cannot blacklist the system memcpy we must use our own naive implementation,
+// copyMemory, for ASan to work on either instrumented or non-instrumented builds. This is not a
+// significant performance loss as tryCopyOtherThreadStack is only called as part of an O(heapsize)
+// operation. As the heap is generally much larger than the stack the performance hit is minimal.
+// See: https://bugs.webkit.org/show_bug.cgi?id=146297
+void MachineThreads::tryCopyOtherThreadStack(Thread* thread, void* buffer, size_t capacity, size_t* size)
+{
+ Thread::Registers registers;
+ size_t registersSize = thread->getRegisters(registers);
+ std::pair<void*, size_t> stack = thread->captureStack(registers.stackPointer());
+
+ bool canCopy = *size + registersSize + stack.second <= capacity;
+
+ if (canCopy)
+ copyMemory(static_cast<char*>(buffer) + *size, ®isters, registersSize);
+ *size += registersSize;