summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/loader/AutoMemMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/xpconnect/loader/AutoMemMap.cpp')
-rw-r--r--js/xpconnect/loader/AutoMemMap.cpp158
1 files changed, 158 insertions, 0 deletions
diff --git a/js/xpconnect/loader/AutoMemMap.cpp b/js/xpconnect/loader/AutoMemMap.cpp
new file mode 100644
index 0000000000..7ce26a9a33
--- /dev/null
+++ b/js/xpconnect/loader/AutoMemMap.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AutoMemMap.h"
+#include "ScriptPreloader-inl.h"
+
+#include "mozilla/Unused.h"
+#include "mozilla/Try.h"
+#include "mozilla/ipc/FileDescriptor.h"
+#include "nsIFile.h"
+
+#include <private/pprio.h>
+
+namespace mozilla {
+namespace loader {
+
+using namespace mozilla::ipc;
+
+AutoMemMap::~AutoMemMap() { reset(); }
+
+FileDescriptor AutoMemMap::cloneFileDescriptor() const {
+ if (fd.get()) {
+ auto handle =
+ FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(fd.get()));
+ return FileDescriptor(handle);
+ }
+ return FileDescriptor();
+}
+
+Result<Ok, nsresult> AutoMemMap::init(nsIFile* file, int flags, int mode,
+ PRFileMapProtect prot) {
+ MOZ_ASSERT(!fd);
+
+ MOZ_TRY(file->OpenNSPRFileDesc(flags, mode, getter_Transfers(fd)));
+
+ return initInternal(prot);
+}
+
+Result<Ok, nsresult> AutoMemMap::init(const FileDescriptor& file,
+ PRFileMapProtect prot, size_t maybeSize) {
+ MOZ_ASSERT(!fd);
+ if (!file.IsValid()) {
+ return Err(NS_ERROR_INVALID_ARG);
+ }
+
+ auto handle = file.ClonePlatformHandle();
+
+ fd.reset(PR_ImportFile(PROsfd(handle.get())));
+ if (!fd) {
+ return Err(NS_ERROR_FAILURE);
+ }
+ Unused << handle.release();
+
+ return initInternal(prot, maybeSize);
+}
+
+Result<Ok, nsresult> AutoMemMap::initInternal(PRFileMapProtect prot,
+ size_t maybeSize) {
+ MOZ_ASSERT(!fileMap);
+ MOZ_ASSERT(!addr);
+
+ if (maybeSize > 0) {
+ // Some OSes' shared memory objects can't be stat()ed, either at
+ // all (Android) or without loosening the sandbox (Mac) so just
+ // use the size.
+ size_ = maybeSize;
+ } else {
+ // But if we don't have the size, assume it's a regular file and
+ // ask for it.
+ PRFileInfo64 fileInfo;
+ MOZ_TRY(PR_GetOpenFileInfo64(fd.get(), &fileInfo));
+
+ if (fileInfo.size > UINT32_MAX) {
+ return Err(NS_ERROR_INVALID_ARG);
+ }
+ size_ = fileInfo.size;
+ }
+
+ fileMap = PR_CreateFileMap(fd.get(), 0, prot);
+ if (!fileMap) {
+ return Err(NS_ERROR_FAILURE);
+ }
+
+ addr = PR_MemMap(fileMap, 0, size_);
+ if (!addr) {
+ return Err(NS_ERROR_FAILURE);
+ }
+
+ return Ok();
+}
+
+#ifdef XP_WIN
+
+Result<Ok, nsresult> AutoMemMap::initWithHandle(const FileDescriptor& file,
+ size_t size,
+ PRFileMapProtect prot) {
+ MOZ_ASSERT(!fd);
+ MOZ_ASSERT(!handle_);
+ if (!file.IsValid()) {
+ return Err(NS_ERROR_INVALID_ARG);
+ }
+
+ handle_ = file.ClonePlatformHandle().release();
+
+ MOZ_ASSERT(!addr);
+
+ size_ = size;
+
+ addr = MapViewOfFile(
+ handle_, prot == PR_PROT_READONLY ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
+ 0, 0, size);
+ if (!addr) {
+ return Err(NS_ERROR_FAILURE);
+ }
+
+ return Ok();
+}
+
+FileDescriptor AutoMemMap::cloneHandle() const {
+ return FileDescriptor(handle_);
+}
+
+#else
+
+Result<Ok, nsresult> AutoMemMap::initWithHandle(const FileDescriptor& file,
+ size_t size,
+ PRFileMapProtect prot) {
+ MOZ_DIAGNOSTIC_ASSERT(size > 0);
+ return init(file, prot, size);
+}
+
+FileDescriptor AutoMemMap::cloneHandle() const { return cloneFileDescriptor(); }
+
+#endif
+
+void AutoMemMap::reset() {
+ if (addr && !persistent_) {
+ Unused << NS_WARN_IF(PR_MemUnmap(addr, size()) != PR_SUCCESS);
+ addr = nullptr;
+ }
+ if (fileMap) {
+ Unused << NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS);
+ fileMap = nullptr;
+ }
+#ifdef XP_WIN
+ if (handle_) {
+ CloseHandle(handle_);
+ handle_ = nullptr;
+ }
+#endif
+ fd = nullptr;
+}
+
+} // namespace loader
+} // namespace mozilla