Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/ipc/MemMapSnapshot.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* vim: set ts=8 sts=4 et sw=4 tw=99: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "MemMapSnapshot.h"
8
9
#include "base/eintr_wrapper.h"
10
#include "base/file_util.h"
11
#include "mozilla/ResultExtensions.h"
12
#include "mozilla/ScopeExit.h"
13
#include "mozilla/ipc/FileDescriptorUtils.h"
14
#include "nsIFile.h"
15
16
#ifdef XP_UNIX
17
#  include <sys/stat.h>
18
#endif
19
20
namespace mozilla {
21
22
using loader::AutoMemMap;
23
24
namespace ipc {
25
26
Result<Ok, nsresult>
27
MemMapSnapshot::Init(size_t aSize)
28
0
{
29
0
  MOZ_ASSERT(!mInitialized);
30
0
31
0
  MOZ_TRY(Create(aSize));
32
0
33
0
  mInitialized = true;
34
0
  return Ok();
35
0
}
36
37
Result<Ok, nsresult>
38
MemMapSnapshot::Finalize(AutoMemMap& aMem)
39
0
{
40
0
  MOZ_ASSERT(mInitialized);
41
0
42
0
  MOZ_TRY(Freeze(aMem));
43
0
44
0
  mInitialized = false;
45
0
  return Ok();
46
0
}
47
48
#if defined(XP_WIN)
49
50
Result<Ok, nsresult>
51
MemMapSnapshot::Create(size_t aSize)
52
{
53
  HANDLE handle = CreateFileMapping(
54
      INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE,
55
      0, DWORD(aSize), nullptr);
56
57
  if (!handle) {
58
    return Err(NS_ERROR_FAILURE);
59
  }
60
61
  mFile.emplace(handle);
62
  return mMem.initWithHandle(mFile.ref(), aSize, PR_PROT_READWRITE);
63
}
64
65
Result<Ok, nsresult>
66
MemMapSnapshot::Freeze(AutoMemMap& aMem)
67
{
68
  auto orig = mFile.ref().ClonePlatformHandle();
69
  mFile.reset();
70
71
  HANDLE handle;
72
  if (!::DuplicateHandle(GetCurrentProcess(), orig.release(), GetCurrentProcess(),
73
                         &handle, GENERIC_READ | FILE_MAP_READ,
74
                         false, DUPLICATE_CLOSE_SOURCE)) {
75
    return Err(NS_ERROR_FAILURE);
76
  }
77
78
  return aMem.initWithHandle(FileDescriptor(handle), mMem.size());
79
}
80
81
#elif defined(XP_UNIX)
82
83
Result<Ok, nsresult>
84
MemMapSnapshot::Create(size_t aSize)
85
0
{
86
0
  FilePath path;
87
0
  ScopedCloseFile fd(file_util::CreateAndOpenTemporaryShmemFile(&path));
88
0
  if (!fd) {
89
0
    return Err(NS_ERROR_FAILURE);
90
0
  }
91
0
92
0
  if (HANDLE_EINTR(ftruncate(fileno(fd), aSize)) != 0) {
93
0
    return Err(NS_ERROR_FAILURE);
94
0
  }
95
0
96
0
  MOZ_TRY(mMem.init(FILEToFileDescriptor(fd), PR_PROT_READWRITE));
97
0
98
0
  mPath.Assign(path.value().data(), path.value().length());
99
0
  return Ok();
100
0
}
101
102
Result<Ok, nsresult>
103
MemMapSnapshot::Freeze(AutoMemMap& aMem)
104
0
{
105
0
  // Delete the shm file after we're done here, whether we succeed or not. The
106
0
  // open file descriptor will keep it alive until all remaining references
107
0
  // are closed, at which point it will be automatically freed.
108
0
  auto cleanup = MakeScopeExit([&]() {
109
0
    PR_Delete(mPath.get());
110
0
  });
111
0
112
0
  // Make the shm file readonly. This doesn't make a difference in practice,
113
0
  // since we open and share a read-only file descriptor, and then delete the
114
0
  // file. But it doesn't hurt, either.
115
0
  chmod(mPath.get(), 0400);
116
0
117
0
  nsCOMPtr<nsIFile> file;
118
0
  MOZ_TRY(NS_NewNativeLocalFile(mPath, /* followLinks = */ false,
119
0
                                getter_AddRefs(file)));
120
0
121
0
  return aMem.init(file);
122
0
}
123
124
#else
125
#  error "Unsupported build configuration"
126
#endif
127
128
} // namespace ipc
129
} // namespace mozilla