From d09855ae7b347aaaebb4e9dc5a78ecef6d8fd62e Mon Sep 17 00:00:00 2001 From: Mikolaj Boc Date: Fri, 21 Apr 2023 13:42:57 +0200 Subject: [PATCH] Copy memory to buffer when saving files on wasm with threading on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wasm heap uses a shared array buffer, which cannot be fed to FileSystemWritableFileStream.write due to security limitations. Heap memory has to be copied to a temporary buffer for the operation to succeed. This is only done if __EMSCRIPTEN_SHARED_MEMORY__ is on to optimize the non-threading path. Fixes: QTBUG-112881 Pick-to: 6.5 Change-Id: I0d117a8703caf4c17abc67b30df5248a53406d5f Reviewed-by: Aleksandr Reviakin Reviewed-by: Morten Johan Sørvig --- .../platform/wasm/qwasmlocalfileaccess.cpp | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp index 762d5e1a40..80e32d629d 100644 --- a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp +++ b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp @@ -258,6 +258,11 @@ void saveDataToFileInChunks(emscripten::val fileHandle, const QByteArray &data) std::function continuation; }; + static constexpr size_t desiredChunkSize = 1024u; +#if defined(__EMSCRIPTEN_SHARED_MEMORY__) + qstdweb::Uint8Array chunkArray(desiredChunkSize); +#endif + auto state = std::make_shared(); state->written = 0u; state->continuation = [=](val) mutable { @@ -267,11 +272,30 @@ void saveDataToFileInChunks(emscripten::val fileHandle, const QByteArray &data) state.reset(); return; } - static constexpr size_t desiredChunkSize = 1024u; + const auto currentChunkSize = std::min(remaining, desiredChunkSize); - Promise::make(writable, QStringLiteral("write"), { - .thenFunc = state->continuation, - }, val(typed_memory_view(currentChunkSize, data.constData() + state->written))); + +#if defined(__EMSCRIPTEN_SHARED_MEMORY__) + // If shared memory is used, WebAssembly.Memory is instantiated with the 'shared' + // option on. Passing a typed_memory_view to SharedArrayBuffer to + // FileSystemWritableFileStream.write is disallowed by security policies, so we + // need to make a copy of the data to a chunk array buffer. + Promise::make( + writable, QStringLiteral("write"), + { + .thenFunc = state->continuation, + }, + chunkArray.copyFrom(data.constData() + state->written, currentChunkSize) + .val() + .call("subarray", emscripten::val(0), + emscripten::val(currentChunkSize))); +#else + Promise::make(writable, QStringLiteral("write"), + { + .thenFunc = state->continuation, + }, + val(typed_memory_view(currentChunkSize, data.constData() + state->written))); +#endif state->written += currentChunkSize; };