Backed out 4 changesets (bug 1454816) for causing build bustages. CLOSED TREE
Backed out changeset 3e8d2c47138c (bug 1454816) Backed out changeset 80ff20241831 (bug 1454816) Backed out changeset 28c2d6d2a683 (bug 1454816) Backed out changeset 236943ab4142 (bug 1454816)
This commit is contained in:
@@ -2388,7 +2388,7 @@ mozilla::ipc::IPCResult ContentChild::RecvRegisterStringBundles(
|
||||
|
||||
for (auto& descriptor : aDescriptors) {
|
||||
stringBundleService->RegisterContentBundle(
|
||||
descriptor.bundleURL(), descriptor.mapHandle(), descriptor.mapSize());
|
||||
descriptor.bundleURL(), descriptor.mapFile(), descriptor.mapSize());
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
@@ -2401,7 +2401,7 @@ mozilla::ipc::IPCResult ContentChild::RecvUpdateL10nFileSources(
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvUpdateSharedData(
|
||||
SharedMemoryHandle&& aMapHandle, const uint32_t& aMapSize,
|
||||
const FileDescriptor& aMapFile, const uint32_t& aMapSize,
|
||||
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys) {
|
||||
nsTArray<RefPtr<BlobImpl>> blobImpls(aBlobs.Length());
|
||||
for (auto& ipcBlob : aBlobs) {
|
||||
@@ -2409,12 +2409,12 @@ mozilla::ipc::IPCResult ContentChild::RecvUpdateSharedData(
|
||||
}
|
||||
|
||||
if (mSharedData) {
|
||||
mSharedData->Update(std::move(aMapHandle), aMapSize, std::move(blobImpls),
|
||||
mSharedData->Update(aMapFile, aMapSize, std::move(blobImpls),
|
||||
std::move(aChangedKeys));
|
||||
} else {
|
||||
mSharedData =
|
||||
new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
|
||||
std::move(aMapHandle), aMapSize, std::move(blobImpls));
|
||||
aMapFile, aMapSize, std::move(blobImpls));
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
@@ -2482,7 +2482,7 @@ mozilla::ipc::IPCResult ContentChild::RecvRebuildFontList(
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvFontListShmBlockAdded(
|
||||
const uint32_t& aGeneration, const uint32_t& aIndex,
|
||||
SharedMemoryHandle&& aHandle) {
|
||||
base::SharedMemoryHandle&& aHandle) {
|
||||
if (gfxPlatform::Initialized()) {
|
||||
gfxPlatformFontList::PlatformFontList()->ShmBlockAdded(aGeneration, aIndex,
|
||||
std::move(aHandle));
|
||||
|
||||
@@ -120,7 +120,7 @@ class ContentChild final : public PContentChild,
|
||||
const mozilla::dom::ipc::StructuredCloneData& aInitialData,
|
||||
bool aIsReadyForBackgroundProcessing);
|
||||
|
||||
void InitSharedUASheets(Maybe<SharedMemoryHandle>&& aHandle,
|
||||
void InitSharedUASheets(Maybe<base::SharedMemoryHandle>&& aHandle,
|
||||
uintptr_t aAddress);
|
||||
|
||||
void InitGraphicsDeviceData(const ContentDeviceData& aData);
|
||||
@@ -314,7 +314,7 @@ class ContentChild final : public PContentChild,
|
||||
nsTArray<L10nFileSourceDescriptor>&& aDescriptors);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateSharedData(
|
||||
SharedMemoryHandle&& aMapHandle, const uint32_t& aMapSize,
|
||||
const FileDescriptor& aMapFile, const uint32_t& aMapSize,
|
||||
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys);
|
||||
|
||||
mozilla::ipc::IPCResult RecvFontListChanged();
|
||||
@@ -334,7 +334,7 @@ class ContentChild final : public PContentChild,
|
||||
mozilla::ipc::IPCResult RecvRebuildFontList(const bool& aFullRebuild);
|
||||
mozilla::ipc::IPCResult RecvFontListShmBlockAdded(
|
||||
const uint32_t& aGeneration, const uint32_t& aIndex,
|
||||
SharedMemoryHandle&& aHandle);
|
||||
base::SharedMemoryHandle&& aHandle);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateAppLocales(
|
||||
nsTArray<nsCString>&& aAppLocales);
|
||||
@@ -510,9 +510,9 @@ class ContentChild final : public PContentChild,
|
||||
mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
|
||||
XPCOMInitData&& aXPCOMInit, const StructuredCloneData& aInitialData,
|
||||
FullLookAndFeel&& aLookAndFeelData, SystemFontList&& aFontList,
|
||||
Maybe<SharedMemoryHandle>&& aSharedUASheetHandle,
|
||||
Maybe<base::SharedMemoryHandle>&& aSharedUASheetHandle,
|
||||
const uintptr_t& aSharedUASheetAddress,
|
||||
nsTArray<SharedMemoryHandle>&& aSharedFontListBlocks,
|
||||
nsTArray<base::SharedMemoryHandle>&& aSharedFontListBlocks,
|
||||
const bool& aIsReadyForBackgroundProcessing);
|
||||
|
||||
mozilla::ipc::IPCResult RecvProvideAnonymousTemporaryFile(
|
||||
@@ -542,7 +542,7 @@ class ContentChild final : public PContentChild,
|
||||
// for use during gfx initialization.
|
||||
SystemFontList& SystemFontList() { return mFontList; }
|
||||
|
||||
nsTArray<SharedMemoryHandle>& SharedFontListBlocks() {
|
||||
nsTArray<base::SharedMemoryHandle>& SharedFontListBlocks() {
|
||||
return mSharedFontListBlocks;
|
||||
}
|
||||
|
||||
@@ -831,7 +831,7 @@ class ContentChild final : public PContentChild,
|
||||
// Temporary storage for look and feel data.
|
||||
FullLookAndFeel mLookAndFeelData;
|
||||
// Temporary storage for list of shared-fontlist memory blocks.
|
||||
nsTArray<SharedMemoryHandle> mSharedFontListBlocks;
|
||||
nsTArray<base::SharedMemoryHandle> mSharedFontListBlocks;
|
||||
|
||||
AppInfo mAppInfo;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/shared_memory.h"
|
||||
|
||||
#include "ContentParent.h"
|
||||
#include "mozilla/ipc/ProcessUtils.h"
|
||||
@@ -150,7 +151,6 @@
|
||||
#include "mozilla/ipc/Endpoint.h"
|
||||
#include "mozilla/ipc/FileDescriptorUtils.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "mozilla/ipc/TestShellParent.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/layers/ImageBridgeParent.h"
|
||||
@@ -1526,12 +1526,11 @@ void ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray) {
|
||||
|
||||
void ContentParent::BroadcastStringBundle(
|
||||
const StringBundleDescriptor& aBundle) {
|
||||
for (auto* cp : AllProcesses(eLive)) {
|
||||
AutoTArray<StringBundleDescriptor, 1> array;
|
||||
array.AppendElement(StringBundleDescriptor(
|
||||
aBundle.bundleURL(), SharedMemory::CloneHandle(aBundle.mapHandle()),
|
||||
aBundle.mapSize()));
|
||||
Unused << cp->SendRegisterStringBundles(std::move(array));
|
||||
array.AppendElement(aBundle);
|
||||
|
||||
for (auto* cp : AllProcesses(eLive)) {
|
||||
Unused << cp->SendRegisterStringBundles(array);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1545,9 +1544,9 @@ void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration,
|
||||
uint32_t aIndex) {
|
||||
auto* pfl = gfxPlatformFontList::PlatformFontList();
|
||||
for (auto* cp : AllProcesses(eLive)) {
|
||||
SharedMemory::Handle handle =
|
||||
base::SharedMemoryHandle handle =
|
||||
pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
|
||||
if (handle == SharedMemory::NULLHandle()) {
|
||||
if (handle == base::SharedMemory::NULLHandle()) {
|
||||
// If something went wrong here, we just skip it; the child will need to
|
||||
// request the block as needed, at some performance cost.
|
||||
continue;
|
||||
@@ -5681,7 +5680,7 @@ mozilla::ipc::IPCResult ContentParent::RecvShutdownPerfStats(
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvGetFontListShmBlock(
|
||||
const uint32_t& aGeneration, const uint32_t& aIndex,
|
||||
SharedMemory::Handle* aOut) {
|
||||
base::SharedMemoryHandle* aOut) {
|
||||
auto* fontList = gfxPlatformFontList::PlatformFontList();
|
||||
MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
|
||||
fontList->ShareFontListShmBlockToProcess(aGeneration, aIndex, Pid(), aOut);
|
||||
@@ -5733,7 +5732,7 @@ mozilla::ipc::IPCResult ContentParent::RecvStartCmapLoading(
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvGetHyphDict(
|
||||
nsIURI* aURI, SharedMemory::Handle* aOutHandle, uint32_t* aOutSize) {
|
||||
nsIURI* aURI, base::SharedMemoryHandle* aOutHandle, uint32_t* aOutSize) {
|
||||
if (!aURI) {
|
||||
return IPC_FAIL(this, "aURI must not be null.");
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DataMutex.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
@@ -1128,7 +1127,7 @@ class ContentParent final : public PContentParent,
|
||||
|
||||
mozilla::ipc::IPCResult RecvGetFontListShmBlock(
|
||||
const uint32_t& aGeneration, const uint32_t& aIndex,
|
||||
mozilla::ipc::SharedMemory::Handle* aOut);
|
||||
base::SharedMemoryHandle* aOut);
|
||||
|
||||
mozilla::ipc::IPCResult RecvInitializeFamily(const uint32_t& aGeneration,
|
||||
const uint32_t& aFamilyIndex,
|
||||
@@ -1151,8 +1150,8 @@ class ContentParent final : public PContentParent,
|
||||
mozilla::ipc::IPCResult RecvStartCmapLoading(const uint32_t& aGeneration,
|
||||
const uint32_t& aStartIndex);
|
||||
|
||||
mozilla::ipc::IPCResult RecvGetHyphDict(
|
||||
nsIURI* aURIParams, mozilla::ipc::SharedMemory::Handle* aOutHandle,
|
||||
mozilla::ipc::IPCResult RecvGetHyphDict(nsIURI* aURIParams,
|
||||
base::SharedMemoryHandle* aOutHandle,
|
||||
uint32_t* aOutSize);
|
||||
|
||||
mozilla::ipc::IPCResult RecvNotifyBenchmarkResult(const nsAString& aCodecName,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "mozilla/ipc/IOThreadChild.h"
|
||||
|
||||
#include "ContentProcess.h"
|
||||
#include "base/shared_memory.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
||||
@@ -77,7 +78,7 @@ void ContentProcess::InfallibleInit(int aArgc, char* aArgv[]) {
|
||||
geckoargs::sParentBuildID.Get(aArgc, aArgv);
|
||||
|
||||
// command line: -jsInitHandle handle -jsInitLen length
|
||||
Maybe<mozilla::ipc::SharedMemoryHandle> jsInitHandle =
|
||||
Maybe<UniqueFileHandle> jsInitHandle =
|
||||
geckoargs::sJsInitHandle.Get(aArgc, aArgv);
|
||||
Maybe<uint64_t> jsInitLen = geckoargs::sJsInitLen.Get(aArgc, aArgv);
|
||||
|
||||
|
||||
@@ -6,40 +6,39 @@
|
||||
|
||||
#include "MemMapSnapshot.h"
|
||||
|
||||
#include "mozilla/AutoMemMap.h"
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
#include "mozilla/Try.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
Result<Ok, nsresult> MemMapSnapshot::Init(size_t aSize) {
|
||||
MOZ_ASSERT(!mMem);
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
|
||||
auto aMem = MakeRefPtr<SharedMemory>();
|
||||
if (NS_WARN_IF(!aMem->CreateFreezable(aSize))) {
|
||||
if (NS_WARN_IF(!mMem.CreateFreezeable(aSize))) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
if (NS_WARN_IF(!aMem->Map(aSize))) {
|
||||
if (NS_WARN_IF(!mMem.Map(aSize))) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
mMem = std::move(aMem);
|
||||
mInitialized = true;
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<Ok, nsresult> MemMapSnapshot::Finalize(RefPtr<SharedMemory>& aMem) {
|
||||
MOZ_ASSERT(mMem);
|
||||
Result<Ok, nsresult> MemMapSnapshot::Finalize(loader::AutoMemMap& aMem) {
|
||||
MOZ_ASSERT(mInitialized);
|
||||
|
||||
auto size = mMem->Size();
|
||||
if (NS_WARN_IF(!mMem->Freeze())) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
aMem = std::move(mMem);
|
||||
|
||||
// We need to re-map the memory as `Freeze()` unmaps it.
|
||||
if (NS_WARN_IF(!aMem->Map(size))) {
|
||||
if (NS_WARN_IF(!mMem.Freeze())) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
// TakeHandle resets mMem, so call max_size first.
|
||||
size_t size = mMem.max_size();
|
||||
FileDescriptor memHandle(mMem.TakeHandle());
|
||||
MOZ_TRY(aMem.initWithHandle(memHandle, size));
|
||||
|
||||
mInitialized = false;
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,13 +9,17 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/RangedPtr.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "base/shared_memory.h"
|
||||
#include "ErrorList.h"
|
||||
|
||||
namespace mozilla::ipc {
|
||||
namespace mozilla {
|
||||
namespace loader {
|
||||
class AutoMemMap;
|
||||
}
|
||||
|
||||
namespace ipc {
|
||||
|
||||
/**
|
||||
* A helper class for creating a read-only snapshot of memory-mapped data.
|
||||
@@ -31,18 +35,20 @@ namespace mozilla::ipc {
|
||||
class MOZ_RAII MemMapSnapshot {
|
||||
public:
|
||||
Result<Ok, nsresult> Init(size_t aSize);
|
||||
Result<Ok, nsresult> Finalize(RefPtr<SharedMemory>& aMem);
|
||||
Result<Ok, nsresult> Finalize(loader::AutoMemMap& aMap);
|
||||
|
||||
template <typename T>
|
||||
RangedPtr<T> Get() {
|
||||
MOZ_ASSERT(mMem);
|
||||
return {static_cast<T*>(mMem->Memory()), mMem->MaxSize() / sizeof(T)};
|
||||
MOZ_ASSERT(mInitialized);
|
||||
return {static_cast<T*>(mMem.memory()), mMem.max_size() / sizeof(T)};
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<SharedMemory> mMem;
|
||||
base::SharedMemory mMem;
|
||||
bool mInitialized = false;
|
||||
};
|
||||
|
||||
} // namespace mozilla::ipc
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // dom_ipc_MemMapSnapshot_h
|
||||
|
||||
@@ -137,7 +137,7 @@ using mozilla::dom::BrowsingContextInitializer from "mozilla/dom/BrowsingContext
|
||||
using mozilla::dom::PermitUnloadResult from "nsIDocumentViewer.h";
|
||||
using mozilla::dom::MaybeDiscardedWindowContext from "mozilla/dom/WindowContext.h";
|
||||
using mozilla::dom::WindowContextTransaction from "mozilla/dom/WindowContext.h";
|
||||
[MoveOnly] using mozilla::ipc::SharedMemoryHandle from "mozilla/ipc/SharedMemory.h";
|
||||
[MoveOnly] using base::SharedMemoryHandle from "base/shared_memory.h";
|
||||
using gfxSparseBitSet from "gfxFontUtils.h";
|
||||
using FontVisibility from "gfxFontEntry.h";
|
||||
using mozilla::dom::MediaControlAction from "mozilla/dom/MediaControlKeySource.h";
|
||||
@@ -401,7 +401,7 @@ struct VisitedQueryResult
|
||||
struct StringBundleDescriptor
|
||||
{
|
||||
nsCString bundleURL;
|
||||
SharedMemoryHandle mapHandle;
|
||||
FileDescriptor mapFile;
|
||||
uint32_t mapSize;
|
||||
};
|
||||
|
||||
@@ -750,7 +750,7 @@ child:
|
||||
|
||||
async RegisterStringBundles(StringBundleDescriptor[] stringBundles);
|
||||
|
||||
async UpdateSharedData(SharedMemoryHandle aMapHandle, uint32_t aSize,
|
||||
async UpdateSharedData(FileDescriptor mapFile, uint32_t aSize,
|
||||
IPCBlob[] blobs,
|
||||
nsCString[] changedKeys);
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "MemMapSnapshot.h"
|
||||
#include "ScriptPreloader-inl.h"
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/AutoEntryScript.h"
|
||||
#include "mozilla/dom/BlobImpl.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
@@ -42,12 +41,12 @@ static inline void AlignTo(size_t* aOffset, size_t aAlign) {
|
||||
|
||||
SharedMap::SharedMap() = default;
|
||||
|
||||
SharedMap::SharedMap(nsIGlobalObject* aGlobal, SharedMemoryHandle&& aMapHandle,
|
||||
SharedMap::SharedMap(nsIGlobalObject* aGlobal, const FileDescriptor& aMapFile,
|
||||
size_t aMapSize, nsTArray<RefPtr<BlobImpl>>&& aBlobs)
|
||||
: DOMEventTargetHelper(aGlobal),
|
||||
mBlobImpls(std::move(aBlobs)),
|
||||
mMapHandle(std::move(aMapHandle)),
|
||||
mMapSize(aMapSize) {}
|
||||
: DOMEventTargetHelper(aGlobal), mBlobImpls(std::move(aBlobs)) {
|
||||
mMapFile.reset(new FileDescriptor(aMapFile));
|
||||
mMapSize = aMapSize;
|
||||
}
|
||||
|
||||
bool SharedMap::Has(const nsACString& aName) {
|
||||
Unused << MaybeRebuild();
|
||||
@@ -97,20 +96,24 @@ void SharedMap::Entry::Read(JSContext* aCx,
|
||||
holder.Read(aCx, aRetVal, aRv);
|
||||
}
|
||||
|
||||
SharedMap::SharedMemoryHandle SharedMap::CloneHandle() const {
|
||||
if (mMap->IsValid()) {
|
||||
return mMap->CloneHandle();
|
||||
FileDescriptor SharedMap::CloneMapFile() const {
|
||||
if (mMap.initialized()) {
|
||||
return mMap.cloneHandle();
|
||||
}
|
||||
return SharedMemory::CloneHandle(mMapHandle);
|
||||
return *mMapFile;
|
||||
}
|
||||
|
||||
void SharedMap::Update(SharedMemoryHandle&& aMapHandle, size_t aMapSize,
|
||||
void SharedMap::Update(const FileDescriptor& aMapFile, size_t aMapSize,
|
||||
nsTArray<RefPtr<BlobImpl>>&& aBlobs,
|
||||
nsTArray<nsCString>&& aChangedKeys) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mWritable);
|
||||
|
||||
mMap->TakeHandleAndUnmap();
|
||||
mMapHandle = std::move(aMapHandle);
|
||||
mMap.reset();
|
||||
if (mMapFile) {
|
||||
*mMapFile = aMapFile;
|
||||
} else {
|
||||
mMapFile.reset(new FileDescriptor(aMapFile));
|
||||
}
|
||||
mMapSize = aMapSize;
|
||||
mEntries.Clear();
|
||||
mEntryArray.reset();
|
||||
@@ -191,7 +194,7 @@ void SharedMap::Entry::ExtractData(char* aDestPtr, uint32_t aNewOffset,
|
||||
}
|
||||
|
||||
Result<Ok, nsresult> SharedMap::MaybeRebuild() {
|
||||
if (!SharedMemory::IsHandleValid(mMapHandle)) {
|
||||
if (!mMapFile) {
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@@ -203,19 +206,13 @@ Result<Ok, nsresult> SharedMap::MaybeRebuild() {
|
||||
// its shared memory region. When needed, that structured clone data is
|
||||
// retrieved directly as indexes into the SharedMap's shared memory region.
|
||||
|
||||
if (!mMap->SetHandle(SharedMemory::CloneHandle(mMapHandle),
|
||||
SharedMemory::OpenRights::RightsReadOnly)) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
mMapHandle = SharedMemory::NULLHandle();
|
||||
if (!mMap->Map(mMapSize)) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
MOZ_TRY(mMap.initWithHandle(*mMapFile, mMapSize));
|
||||
mMapFile.reset();
|
||||
|
||||
// We should be able to pass this range as an initializer list or an immediate
|
||||
// param, but gcc currently chokes on that if optimization is enabled, and
|
||||
// initializes everything to 0.
|
||||
Range<uint8_t> range((uint8_t*)mMap->Memory(), mMap->Size());
|
||||
Range<uint8_t> range(&mMap.get<uint8_t>()[0], mMap.size());
|
||||
InputBuffer buffer(range);
|
||||
|
||||
uint32_t count;
|
||||
@@ -248,7 +245,7 @@ WritableSharedMap::WritableSharedMap() {
|
||||
// Serialize the initial empty contents of the map immediately so that we
|
||||
// always have a file descriptor to send to callers of CloneMapFile().
|
||||
Unused << Serialize();
|
||||
MOZ_RELEASE_ASSERT(mMap->IsValid());
|
||||
MOZ_RELEASE_ASSERT(mMap.initialized());
|
||||
}
|
||||
|
||||
SharedMap* WritableSharedMap::GetReadOnly() {
|
||||
@@ -256,7 +253,7 @@ SharedMap* WritableSharedMap::GetReadOnly() {
|
||||
nsTArray<RefPtr<BlobImpl>> blobs(mBlobImpls.Clone());
|
||||
mReadOnly =
|
||||
new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
|
||||
CloneHandle(), MapSize(), std::move(blobs));
|
||||
CloneMapFile(), MapSize(), std::move(blobs));
|
||||
}
|
||||
return mReadOnly;
|
||||
}
|
||||
@@ -339,7 +336,7 @@ Result<Ok, nsresult> WritableSharedMap::Serialize() {
|
||||
memcpy(ptr.get(), header.Get(), header.cursor());
|
||||
|
||||
// We've already updated offsets at this point. We need this to succeed.
|
||||
mMap->TakeHandleAndUnmap();
|
||||
mMap.reset();
|
||||
MOZ_RELEASE_ASSERT(mem.Finalize(mMap).isOk());
|
||||
|
||||
return Ok();
|
||||
@@ -355,7 +352,7 @@ void WritableSharedMap::SendTo(ContentParent* aParent) const {
|
||||
}
|
||||
}
|
||||
|
||||
Unused << aParent->SendUpdateSharedData(CloneHandle(), mMap->Size(), blobs,
|
||||
Unused << aParent->SendUpdateSharedData(CloneMapFile(), mMap.size(), blobs,
|
||||
mChangedKeys);
|
||||
}
|
||||
|
||||
@@ -376,7 +373,7 @@ void WritableSharedMap::BroadcastChanges() {
|
||||
|
||||
if (mReadOnly) {
|
||||
nsTArray<RefPtr<BlobImpl>> blobImpls(mBlobImpls.Clone());
|
||||
mReadOnly->Update(CloneHandle(), mMap->Size(), std::move(blobImpls),
|
||||
mReadOnly->Update(CloneMapFile(), mMap.size(), std::move(blobImpls),
|
||||
std::move(mChangedKeys));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
#include "mozilla/dom/MozSharedMapBinding.h"
|
||||
|
||||
#include "mozilla/AutoMemMap.h"
|
||||
#include "mozilla/dom/ipc/StructuredCloneData.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
@@ -53,13 +53,12 @@ namespace ipc {
|
||||
* WritableSharedMap instances.
|
||||
*/
|
||||
class SharedMap : public DOMEventTargetHelper {
|
||||
using SharedMemory = mozilla::ipc::SharedMemory;
|
||||
using SharedMemoryHandle = mozilla::ipc::SharedMemoryHandle;
|
||||
using FileDescriptor = mozilla::ipc::FileDescriptor;
|
||||
|
||||
public:
|
||||
SharedMap();
|
||||
|
||||
SharedMap(nsIGlobalObject* aGlobal, SharedMemoryHandle&&, size_t,
|
||||
SharedMap(nsIGlobalObject* aGlobal, const FileDescriptor&, size_t,
|
||||
nsTArray<RefPtr<BlobImpl>>&& aBlobs);
|
||||
|
||||
// Returns true if the map contains the given (UTF-8) key.
|
||||
@@ -97,7 +96,7 @@ class SharedMap : public DOMEventTargetHelper {
|
||||
* memory region for this map. The file descriptor may be passed between
|
||||
* processes, and used to update corresponding instances in child processes.
|
||||
*/
|
||||
SharedMemoryHandle CloneHandle() const;
|
||||
FileDescriptor CloneMapFile() const;
|
||||
|
||||
/**
|
||||
* Returns the size of the memory mapped region that backs this map. Must be
|
||||
@@ -105,14 +104,14 @@ class SharedMap : public DOMEventTargetHelper {
|
||||
* descriptor returned by CloneMapFile() in order to initialize or update a
|
||||
* child SharedMap.
|
||||
*/
|
||||
size_t MapSize() const { return mMap->Size(); }
|
||||
size_t MapSize() const { return mMap.size(); }
|
||||
|
||||
/**
|
||||
* Updates this instance to reflect the contents of the shared memory region
|
||||
* in the given map handle, and broadcasts a change event for the given set of
|
||||
* in the given map file, and broadcasts a change event for the given set of
|
||||
* changed (UTF-8-encoded) keys.
|
||||
*/
|
||||
void Update(SharedMemoryHandle&& aMapHandle, size_t aMapSize,
|
||||
void Update(const FileDescriptor& aMapFile, size_t aMapSize,
|
||||
nsTArray<RefPtr<BlobImpl>>&& aBlobs,
|
||||
nsTArray<nsCString>&& aChangedKeys);
|
||||
|
||||
@@ -263,8 +262,12 @@ class SharedMap : public DOMEventTargetHelper {
|
||||
Result<Ok, nsresult> MaybeRebuild();
|
||||
void MaybeRebuild() const;
|
||||
|
||||
SharedMemoryHandle mMapHandle;
|
||||
// The size of the memory-mapped region backed by mMap, in bytes.
|
||||
// Note: This header is included by WebIDL binding headers, and therefore
|
||||
// can't include "windows.h". Since FileDescriptor.h does include "windows.h"
|
||||
// on Windows, we can only forward declare FileDescriptor, and can't include
|
||||
// it as an inline member.
|
||||
UniquePtr<FileDescriptor> mMapFile;
|
||||
// The size of the memory-mapped region backed by mMapFile, in bytes.
|
||||
size_t mMapSize = 0;
|
||||
|
||||
mutable nsClassHashtable<nsCStringHashKey, Entry> mEntries;
|
||||
@@ -273,14 +276,14 @@ class SharedMap : public DOMEventTargetHelper {
|
||||
// Manages the memory mapping of the current snapshot. This is initialized
|
||||
// lazily after each SharedMap construction or updated, based on the values in
|
||||
// mMapFile and mMapSize.
|
||||
RefPtr<SharedMemory> mMap = MakeRefPtr<SharedMemory>();
|
||||
loader::AutoMemMap mMap;
|
||||
|
||||
bool mWritable = false;
|
||||
|
||||
// Returns a pointer to the beginning of the memory mapped snapshot. Entry
|
||||
// offsets are relative to this pointer, and Entry objects access their
|
||||
// structured clone data by indexing this pointer.
|
||||
char* Data() { return static_cast<char*>(mMap->Memory()); }
|
||||
char* Data() { return mMap.get<char>().get(); }
|
||||
};
|
||||
|
||||
class WritableSharedMap final : public SharedMap {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "mozilla/BinarySearch.h"
|
||||
#include "mozilla/Try.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
|
||||
using namespace mozilla::loader;
|
||||
|
||||
@@ -27,42 +28,27 @@ static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) {
|
||||
return mod ? aAlign - mod : 0;
|
||||
}
|
||||
|
||||
SharedStringMap::SharedStringMap(const SharedMemoryHandle& aMapHandle,
|
||||
SharedStringMap::SharedStringMap(const FileDescriptor& aMapFile,
|
||||
size_t aMapSize) {
|
||||
auto map = MakeRefPtr<SharedMemory>();
|
||||
{
|
||||
auto result = map->SetHandle(SharedMemory::CloneHandle(aMapHandle),
|
||||
SharedMemory::OpenRights::RightsReadOnly);
|
||||
MOZ_RELEASE_ASSERT(result);
|
||||
}
|
||||
{
|
||||
auto result = map->Map(aMapSize);
|
||||
MOZ_RELEASE_ASSERT(result);
|
||||
}
|
||||
|
||||
auto result = mMap.initWithHandle(aMapFile, aMapSize);
|
||||
MOZ_RELEASE_ASSERT(result.isOk());
|
||||
MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic);
|
||||
// We return literal nsStrings and nsCStrings pointing to the mapped data,
|
||||
// which means that we may still have references to the mapped data even
|
||||
// after this instance is destroyed. That means that we need to keep the
|
||||
// mapping alive until process shutdown, in order to be safe.
|
||||
mMappedMemory = map->TakeMapping();
|
||||
mHandle = map->TakeHandle();
|
||||
|
||||
MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic);
|
||||
mMap.setPersistent();
|
||||
}
|
||||
|
||||
SharedStringMap::SharedStringMap(SharedStringMapBuilder&& aBuilder) {
|
||||
RefPtr<SharedMemory> map;
|
||||
auto result = aBuilder.Finalize(map);
|
||||
MOZ_RELEASE_ASSERT(result.isOk() && map);
|
||||
|
||||
mMappedMemory = map->TakeMapping();
|
||||
mHandle = map->TakeHandle();
|
||||
|
||||
auto result = aBuilder.Finalize(mMap);
|
||||
MOZ_RELEASE_ASSERT(result.isOk());
|
||||
MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic);
|
||||
mMap.setPersistent();
|
||||
}
|
||||
|
||||
mozilla::ipc::SharedMemoryHandle SharedStringMap::CloneHandle() const {
|
||||
return SharedMemory::CloneHandle(mHandle);
|
||||
mozilla::ipc::FileDescriptor SharedStringMap::CloneFileDescriptor() const {
|
||||
return mMap.cloneHandle();
|
||||
}
|
||||
|
||||
bool SharedStringMap::Has(const nsCString& aKey) {
|
||||
@@ -98,7 +84,7 @@ void SharedStringMapBuilder::Add(const nsCString& aKey,
|
||||
}
|
||||
|
||||
Result<Ok, nsresult> SharedStringMapBuilder::Finalize(
|
||||
RefPtr<SharedMemory>& aMap) {
|
||||
loader::AutoMemMap& aMap) {
|
||||
using Header = SharedStringMap::Header;
|
||||
|
||||
MOZ_ASSERT(mEntries.Count() == mKeyTable.Count());
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#ifndef dom_ipc_SharedStringMap_h
|
||||
#define dom_ipc_SharedStringMap_h
|
||||
|
||||
#include "mozilla/AutoMemMap.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/dom/ipc/StringTable.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "nsTHashMap.h"
|
||||
|
||||
namespace mozilla::dom::ipc {
|
||||
@@ -30,6 +30,8 @@ class SharedStringMapBuilder;
|
||||
* freed before process shutdown. Do not use it for short-lived mappings.
|
||||
*/
|
||||
class SharedStringMap {
|
||||
using FileDescriptor = mozilla::ipc::FileDescriptor;
|
||||
|
||||
public:
|
||||
/**
|
||||
* The header at the beginning of the shared memory region describing its
|
||||
@@ -88,7 +90,7 @@ class SharedStringMap {
|
||||
// Note: These constructors are infallible on the premise that this class
|
||||
// is used primarily in cases where it is critical to platform
|
||||
// functionality.
|
||||
explicit SharedStringMap(const mozilla::ipc::SharedMemoryHandle&, size_t);
|
||||
explicit SharedStringMap(const FileDescriptor&, size_t);
|
||||
explicit SharedStringMap(SharedStringMapBuilder&&);
|
||||
|
||||
/**
|
||||
@@ -146,23 +148,21 @@ class SharedStringMap {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the read-only shared memory handle which backs the shared
|
||||
* memory region for this map. The handle may be passed between processes, and
|
||||
* used to construct new instances of SharedStringMap with the same data as
|
||||
* this instance.
|
||||
* Returns a copy of the read-only file descriptor which backs the shared
|
||||
* memory region for this map. The file descriptor may be passed between
|
||||
* processes, and used to construct new instances of SharedStringMap with
|
||||
* the same data as this instance.
|
||||
*/
|
||||
mozilla::ipc::SharedMemoryHandle CloneHandle() const;
|
||||
FileDescriptor CloneFileDescriptor() const;
|
||||
|
||||
size_t MapSize() const { return mMappedMemory.size(); }
|
||||
size_t MapSize() const { return mMap.size(); }
|
||||
|
||||
protected:
|
||||
~SharedStringMap() = default;
|
||||
|
||||
private:
|
||||
// Type-safe getters for values in the shared memory region:
|
||||
const Header& GetHeader() const {
|
||||
return *reinterpret_cast<const Header*>(mMappedMemory.data());
|
||||
}
|
||||
const Header& GetHeader() const { return mMap.get<Header>()[0]; }
|
||||
|
||||
RangedPtr<const Entry> Entries() const {
|
||||
return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()};
|
||||
@@ -171,22 +171,18 @@ class SharedStringMap {
|
||||
uint32_t EntryCount() const { return GetHeader().mEntryCount; }
|
||||
|
||||
StringTable<nsCString> KeyTable() const {
|
||||
const auto& header = GetHeader();
|
||||
return {{&mMappedMemory.data()[header.mKeyStringsOffset],
|
||||
auto& header = GetHeader();
|
||||
return {{&mMap.get<uint8_t>()[header.mKeyStringsOffset],
|
||||
header.mKeyStringsSize}};
|
||||
}
|
||||
|
||||
StringTable<nsString> ValueTable() const {
|
||||
const auto& header = GetHeader();
|
||||
return {{&mMappedMemory.data()[header.mValueStringsOffset],
|
||||
auto& header = GetHeader();
|
||||
return {{&mMap.get<uint8_t>()[header.mValueStringsOffset],
|
||||
header.mValueStringsSize}};
|
||||
}
|
||||
|
||||
mozilla::ipc::SharedMemoryHandle mHandle;
|
||||
// This is a leaked shared memory mapping (see the constructor definition for
|
||||
// an explanation). It replaces AutoMemMap::setPersistent behavior as part of
|
||||
// bug 1454816.
|
||||
Span<uint8_t> mMappedMemory;
|
||||
loader::AutoMemMap mMap;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -205,10 +201,10 @@ class MOZ_RAII SharedStringMapBuilder {
|
||||
|
||||
/**
|
||||
* Finalizes the binary representation of the map, writes it to a shared
|
||||
* memory region, and then initializes the given SharedMemory with a reference
|
||||
* memory region, and then initializes the given AutoMemMap with a reference
|
||||
* to the read-only copy of it.
|
||||
*/
|
||||
Result<Ok, nsresult> Finalize(RefPtr<mozilla::ipc::SharedMemory>& aMap);
|
||||
Result<Ok, nsresult> Finalize(loader::AutoMemMap& aMap);
|
||||
|
||||
private:
|
||||
using Entry = SharedStringMap::Entry;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
# include "mozilla/SandboxInfo.h"
|
||||
# include "mozilla/ipc/SharedMemory.h"
|
||||
# include "base/shared_memory.h"
|
||||
#endif
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/SSE.h"
|
||||
@@ -302,7 +302,7 @@ class NotifyGMPProcessLoadedTask : public Runnable {
|
||||
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
if (SandboxInfo::Get().Test(SandboxInfo::kEnabledForMedia) &&
|
||||
ipc::SharedMemory::UsingPosixShm()) {
|
||||
base::SharedMemory::UsingPosixShm()) {
|
||||
canProfile = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
|
||||
#include "SharedFontList.h"
|
||||
|
||||
#include "base/process.h"
|
||||
#include "base/shared_memory.h"
|
||||
|
||||
#include "gfxFontUtils.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsTHashMap.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
// This is split out from SharedFontList.h because that header is included
|
||||
// quite widely (via gfxPlatformFontList.h, gfxTextRun.h, etc), and other code
|
||||
@@ -243,11 +242,11 @@ class FontList {
|
||||
* list has changed/grown since the child was first initialized).
|
||||
*/
|
||||
void ShareShmBlockToProcess(uint32_t aIndex, base::ProcessId aPid,
|
||||
ipc::SharedMemory::Handle* aOut) {
|
||||
base::SharedMemoryHandle* aOut) {
|
||||
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
|
||||
if (aIndex >= mReadOnlyShmems.Length()) {
|
||||
// Block index out of range
|
||||
*aOut = ipc::SharedMemory::NULLHandle();
|
||||
*aOut = base::SharedMemory::NULLHandle();
|
||||
return;
|
||||
}
|
||||
*aOut = mReadOnlyShmems[aIndex]->CloneHandle();
|
||||
@@ -261,14 +260,14 @@ class FontList {
|
||||
* shared to the given process. This is used at child process startup
|
||||
* to pass the complete list at once.
|
||||
*/
|
||||
void ShareBlocksToProcess(nsTArray<ipc::SharedMemory::Handle>* aBlocks,
|
||||
void ShareBlocksToProcess(nsTArray<base::SharedMemoryHandle>* aBlocks,
|
||||
base::ProcessId aPid);
|
||||
|
||||
ipc::SharedMemory::Handle ShareBlockToProcess(uint32_t aIndex,
|
||||
base::SharedMemoryHandle ShareBlockToProcess(uint32_t aIndex,
|
||||
base::ProcessId aPid);
|
||||
|
||||
void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
||||
ipc::SharedMemory::Handle aHandle);
|
||||
base::SharedMemoryHandle aHandle);
|
||||
/**
|
||||
* Support for memory reporter.
|
||||
*/
|
||||
@@ -300,11 +299,11 @@ class FontList {
|
||||
struct ShmBlock {
|
||||
// Takes ownership of aShmem. Note that in a child process, aShmem will be
|
||||
// mapped as read-only.
|
||||
explicit ShmBlock(RefPtr<ipc::SharedMemory>&& aShmem)
|
||||
explicit ShmBlock(mozilla::UniquePtr<base::SharedMemory>&& aShmem)
|
||||
: mShmem(std::move(aShmem)) {}
|
||||
|
||||
// Get pointer to the mapped memory.
|
||||
void* Memory() const { return mShmem->Memory(); }
|
||||
void* Memory() const { return mShmem->memory(); }
|
||||
|
||||
// Only the parent process does allocation, so only it will update this
|
||||
// field. Content processes read the value when checking Pointer validity.
|
||||
@@ -326,7 +325,7 @@ class FontList {
|
||||
return static_cast<BlockHeader*>(Memory())->mBlockSize;
|
||||
}
|
||||
|
||||
RefPtr<ipc::SharedMemory> mShmem;
|
||||
mozilla::UniquePtr<base::SharedMemory> mShmem;
|
||||
};
|
||||
|
||||
Header& GetHeader() const;
|
||||
@@ -372,7 +371,7 @@ class FontList {
|
||||
* Auxiliary array, used only in the parent process; holds read-only copies
|
||||
* of the shmem blocks; these are what will be shared to child processes.
|
||||
*/
|
||||
nsTArray<RefPtr<ipc::SharedMemory>> mReadOnlyShmems;
|
||||
nsTArray<mozilla::UniquePtr<base::SharedMemory>> mReadOnlyShmems;
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Bool array to track whether we have read face names from the name table.
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "gfxPlatformFontList.h"
|
||||
#include "gfxFontUtils.h"
|
||||
#include "gfxFont.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "prerror.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
@@ -739,23 +738,22 @@ FontList::FontList(uint32_t aGeneration) {
|
||||
// SetXPCOMProcessAttributes.
|
||||
auto& blocks = dom::ContentChild::GetSingleton()->SharedFontListBlocks();
|
||||
for (auto& handle : blocks) {
|
||||
auto newShm = MakeRefPtr<ipc::SharedMemory>();
|
||||
auto newShm = MakeUnique<base::SharedMemory>();
|
||||
if (!newShm->IsHandleValid(handle)) {
|
||||
// Bail out and let UpdateShmBlocks try to do its thing below.
|
||||
break;
|
||||
}
|
||||
if (!newShm->SetHandle(std::move(handle),
|
||||
ipc::SharedMemory::OpenRights::RightsReadOnly)) {
|
||||
if (!newShm->SetHandle(std::move(handle), true)) {
|
||||
MOZ_CRASH("failed to set shm handle");
|
||||
}
|
||||
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->Memory()) {
|
||||
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->memory()) {
|
||||
MOZ_CRASH("failed to map shared memory");
|
||||
}
|
||||
uint32_t size = static_cast<BlockHeader*>(newShm->Memory())->mBlockSize;
|
||||
uint32_t size = static_cast<BlockHeader*>(newShm->memory())->mBlockSize;
|
||||
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
|
||||
if (size != SHM_BLOCK_SIZE) {
|
||||
newShm->Unmap();
|
||||
if (!newShm->Map(size) || !newShm->Memory()) {
|
||||
if (!newShm->Map(size) || !newShm->memory()) {
|
||||
MOZ_CRASH("failed to map shared memory");
|
||||
}
|
||||
}
|
||||
@@ -802,16 +800,16 @@ FontList::Header& FontList::GetHeader() const MOZ_NO_THREAD_SAFETY_ANALYSIS {
|
||||
bool FontList::AppendShmBlock(uint32_t aSizeNeeded) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
uint32_t size = std::max(aSizeNeeded, SHM_BLOCK_SIZE);
|
||||
auto newShm = MakeRefPtr<ipc::SharedMemory>();
|
||||
if (!newShm->CreateFreezable(size)) {
|
||||
auto newShm = MakeUnique<base::SharedMemory>();
|
||||
if (!newShm->CreateFreezeable(size)) {
|
||||
MOZ_CRASH("failed to create shared memory");
|
||||
return false;
|
||||
}
|
||||
if (!newShm->Map(size) || !newShm->Memory()) {
|
||||
if (!newShm->Map(size) || !newShm->memory()) {
|
||||
MOZ_CRASH("failed to map shared memory");
|
||||
return false;
|
||||
}
|
||||
auto readOnly = MakeRefPtr<ipc::SharedMemory>();
|
||||
auto readOnly = MakeUnique<base::SharedMemory>();
|
||||
if (!newShm->ReadOnlyCopy(readOnly.get())) {
|
||||
MOZ_CRASH("failed to create read-only copy");
|
||||
return false;
|
||||
@@ -846,16 +844,15 @@ bool FontList::AppendShmBlock(uint32_t aSizeNeeded) {
|
||||
}
|
||||
|
||||
void FontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
||||
ipc::SharedMemory::Handle aHandle) {
|
||||
base::SharedMemoryHandle aHandle) {
|
||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||
MOZ_ASSERT(mBlocks.Length() > 0);
|
||||
|
||||
auto newShm = MakeRefPtr<ipc::SharedMemory>();
|
||||
auto newShm = MakeUnique<base::SharedMemory>();
|
||||
if (!newShm->IsHandleValid(aHandle)) {
|
||||
return;
|
||||
}
|
||||
if (!newShm->SetHandle(std::move(aHandle),
|
||||
ipc::SharedMemory::RightsReadOnly)) {
|
||||
if (!newShm->SetHandle(std::move(aHandle), true)) {
|
||||
MOZ_CRASH("failed to set shm handle");
|
||||
}
|
||||
|
||||
@@ -866,15 +863,15 @@ void FontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->Memory()) {
|
||||
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->memory()) {
|
||||
MOZ_CRASH("failed to map shared memory");
|
||||
}
|
||||
|
||||
uint32_t size = static_cast<BlockHeader*>(newShm->Memory())->mBlockSize;
|
||||
uint32_t size = static_cast<BlockHeader*>(newShm->memory())->mBlockSize;
|
||||
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
|
||||
if (size != SHM_BLOCK_SIZE) {
|
||||
newShm->Unmap();
|
||||
if (!newShm->Map(size) || !newShm->Memory()) {
|
||||
if (!newShm->Map(size) || !newShm->memory()) {
|
||||
MOZ_CRASH("failed to map shared memory");
|
||||
}
|
||||
}
|
||||
@@ -895,27 +892,26 @@ FontList::ShmBlock* FontList::GetBlockFromParent(uint32_t aIndex) {
|
||||
// If we have no existing blocks, we don't want a generation check yet;
|
||||
// the header in the first block will define the generation of this list
|
||||
uint32_t generation = aIndex == 0 ? 0 : GetGeneration();
|
||||
ipc::SharedMemory::Handle handle = ipc::SharedMemory::NULLHandle();
|
||||
base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle();
|
||||
if (!dom::ContentChild::GetSingleton()->SendGetFontListShmBlock(
|
||||
generation, aIndex, &handle)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto newShm = MakeRefPtr<ipc::SharedMemory>();
|
||||
auto newShm = MakeUnique<base::SharedMemory>();
|
||||
if (!newShm->IsHandleValid(handle)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!newShm->SetHandle(std::move(handle),
|
||||
ipc::SharedMemory::RightsReadOnly)) {
|
||||
if (!newShm->SetHandle(std::move(handle), true)) {
|
||||
MOZ_CRASH("failed to set shm handle");
|
||||
}
|
||||
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->Memory()) {
|
||||
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->memory()) {
|
||||
MOZ_CRASH("failed to map shared memory");
|
||||
}
|
||||
uint32_t size = static_cast<BlockHeader*>(newShm->Memory())->mBlockSize;
|
||||
uint32_t size = static_cast<BlockHeader*>(newShm->memory())->mBlockSize;
|
||||
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
|
||||
if (size != SHM_BLOCK_SIZE) {
|
||||
newShm->Unmap();
|
||||
if (!newShm->Map(size) || !newShm->Memory()) {
|
||||
if (!newShm->Map(size) || !newShm->memory()) {
|
||||
MOZ_CRASH("failed to map shared memory");
|
||||
}
|
||||
}
|
||||
@@ -944,8 +940,8 @@ bool FontList::UpdateShmBlocks(bool aMustLock) MOZ_NO_THREAD_SAFETY_ANALYSIS {
|
||||
return result;
|
||||
}
|
||||
|
||||
void FontList::ShareBlocksToProcess(
|
||||
nsTArray<ipc::SharedMemory::Handle>* aBlocks, base::ProcessId aPid) {
|
||||
void FontList::ShareBlocksToProcess(nsTArray<base::SharedMemoryHandle>* aBlocks,
|
||||
base::ProcessId aPid) {
|
||||
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
|
||||
for (auto& shmem : mReadOnlyShmems) {
|
||||
auto handle = shmem->CloneHandle();
|
||||
@@ -961,7 +957,7 @@ void FontList::ShareBlocksToProcess(
|
||||
}
|
||||
}
|
||||
|
||||
ipc::SharedMemory::Handle FontList::ShareBlockToProcess(uint32_t aIndex,
|
||||
base::SharedMemoryHandle FontList::ShareBlockToProcess(uint32_t aIndex,
|
||||
base::ProcessId aPid) {
|
||||
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
|
||||
|
||||
@@ -3044,7 +3044,7 @@ void gfxPlatformFontList::CancelInitOtherFamilyNamesTask() {
|
||||
|
||||
void gfxPlatformFontList::ShareFontListShmBlockToProcess(
|
||||
uint32_t aGeneration, uint32_t aIndex, base::ProcessId aPid,
|
||||
mozilla::ipc::SharedMemory::Handle* aOut) {
|
||||
base::SharedMemoryHandle* aOut) {
|
||||
auto list = SharedFontList();
|
||||
if (!list) {
|
||||
return;
|
||||
@@ -3052,28 +3052,26 @@ void gfxPlatformFontList::ShareFontListShmBlockToProcess(
|
||||
if (!aGeneration || list->GetGeneration() == aGeneration) {
|
||||
list->ShareShmBlockToProcess(aIndex, aPid, aOut);
|
||||
} else {
|
||||
*aOut = mozilla::ipc::SharedMemory::NULLHandle();
|
||||
*aOut = base::SharedMemory::NULLHandle();
|
||||
}
|
||||
}
|
||||
|
||||
void gfxPlatformFontList::ShareFontListToProcess(
|
||||
nsTArray<mozilla::ipc::SharedMemory::Handle>* aBlocks,
|
||||
base::ProcessId aPid) {
|
||||
nsTArray<base::SharedMemoryHandle>* aBlocks, base::ProcessId aPid) {
|
||||
auto list = SharedFontList();
|
||||
if (list) {
|
||||
list->ShareBlocksToProcess(aBlocks, aPid);
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::SharedMemory::Handle gfxPlatformFontList::ShareShmBlockToProcess(
|
||||
base::SharedMemoryHandle gfxPlatformFontList::ShareShmBlockToProcess(
|
||||
uint32_t aIndex, base::ProcessId aPid) {
|
||||
MOZ_RELEASE_ASSERT(SharedFontList());
|
||||
return SharedFontList()->ShareBlockToProcess(aIndex, aPid);
|
||||
}
|
||||
|
||||
void gfxPlatformFontList::ShmBlockAdded(
|
||||
uint32_t aGeneration, uint32_t aIndex,
|
||||
mozilla::ipc::SharedMemory::Handle aHandle) {
|
||||
void gfxPlatformFontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
||||
base::SharedMemoryHandle aHandle) {
|
||||
if (SharedFontList()) {
|
||||
AutoLock lock(mLock);
|
||||
SharedFontList()->ShmBlockAdded(aGeneration, aIndex, std::move(aHandle));
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "gfxPlatform.h"
|
||||
#include "SharedFontList.h"
|
||||
|
||||
#include "base/process.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
@@ -27,9 +26,10 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/RangedArray.h"
|
||||
#include "mozilla/RecursiveMutex.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "nsLanguageAtomService.h"
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace fontlist {
|
||||
struct AliasData;
|
||||
@@ -355,19 +355,18 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
||||
// be shared to the given processId.
|
||||
void ShareFontListShmBlockToProcess(uint32_t aGeneration, uint32_t aIndex,
|
||||
base::ProcessId aPid,
|
||||
mozilla::ipc::SharedMemory::Handle* aOut);
|
||||
base::SharedMemoryHandle* aOut);
|
||||
|
||||
// Populate the array aBlocks with the complete list of shmem handles ready
|
||||
// to be shared to the given processId.
|
||||
void ShareFontListToProcess(
|
||||
nsTArray<mozilla::ipc::SharedMemory::Handle>* aBlocks,
|
||||
void ShareFontListToProcess(nsTArray<base::SharedMemoryHandle>* aBlocks,
|
||||
base::ProcessId aPid);
|
||||
|
||||
void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
||||
mozilla::ipc::SharedMemory::Handle aHandle);
|
||||
base::SharedMemoryHandle aHandle);
|
||||
|
||||
mozilla::ipc::SharedMemory::Handle ShareShmBlockToProcess(
|
||||
uint32_t aIndex, base::ProcessId aPid);
|
||||
base::SharedMemoryHandle ShareShmBlockToProcess(uint32_t aIndex,
|
||||
base::ProcessId aPid);
|
||||
|
||||
void SetCharacterMap(uint32_t aGeneration, uint32_t aFamilyIndex, bool aAlias,
|
||||
uint32_t aFaceIndex, const gfxSparseBitSet& aMap);
|
||||
|
||||
@@ -330,11 +330,11 @@ void nsHyphenationManager::LoadAliases() {
|
||||
}
|
||||
|
||||
void nsHyphenationManager::ShareHyphDictToProcess(
|
||||
nsIURI* aURI, base::ProcessId aPid,
|
||||
mozilla::ipc::SharedMemory::Handle* aOutHandle, uint32_t* aOutSize) {
|
||||
nsIURI* aURI, base::ProcessId aPid, base::SharedMemoryHandle* aOutHandle,
|
||||
uint32_t* aOutSize) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
// aURI will be referring to an omnijar resource (otherwise just bail).
|
||||
*aOutHandle = mozilla::ipc::SharedMemory::NULLHandle();
|
||||
*aOutHandle = base::SharedMemory::NULLHandle();
|
||||
*aOutSize = 0;
|
||||
|
||||
// Extract the locale code from the URI, and get the corresponding
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
#ifndef nsHyphenationManager_h__
|
||||
#define nsHyphenationManager_h__
|
||||
|
||||
#include "base/process.h"
|
||||
#include "base/shared_memory.h"
|
||||
#include "mozilla/Omnijar.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsAtomHashKeys.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
@@ -28,7 +27,7 @@ class nsHyphenationManager : public nsIObserver {
|
||||
already_AddRefed<nsHyphenator> GetHyphenator(nsAtom* aLocale);
|
||||
|
||||
void ShareHyphDictToProcess(nsIURI* aURI, base::ProcessId aPid,
|
||||
mozilla::ipc::SharedMemory::Handle* aOutHandle,
|
||||
base::SharedMemoryHandle* aOutHandle,
|
||||
uint32_t* aOutSize);
|
||||
|
||||
static nsHyphenationManager* Instance();
|
||||
|
||||
@@ -66,27 +66,27 @@ static const void* GetItemPtrFromJarURI(nsIJARURI* aJAR, uint32_t* aLength) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static RefPtr<ipc::SharedMemory> GetHyphDictFromParent(nsIURI* aURI,
|
||||
static UniquePtr<base::SharedMemory> GetHyphDictFromParent(nsIURI* aURI,
|
||||
uint32_t* aLength) {
|
||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||
ipc::SharedMemory::Handle handle = ipc::SharedMemory::NULLHandle();
|
||||
base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle();
|
||||
uint32_t size;
|
||||
MOZ_ASSERT(aURI);
|
||||
if (!dom::ContentChild::GetSingleton()->SendGetHyphDict(aURI, &handle,
|
||||
&size)) {
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<ipc::SharedMemory> shm = MakeRefPtr<ipc::SharedMemory>();
|
||||
UniquePtr<base::SharedMemory> shm = MakeUnique<base::SharedMemory>();
|
||||
if (!shm->IsHandleValid(handle)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!shm->SetHandle(std::move(handle), ipc::SharedMemory::RightsReadOnly)) {
|
||||
if (!shm->SetHandle(std::move(handle), true)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!shm->Map(size)) {
|
||||
return nullptr;
|
||||
}
|
||||
char* addr = static_cast<char*>(shm->Memory());
|
||||
char* addr = static_cast<char*>(shm->memory());
|
||||
if (!addr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -94,21 +94,21 @@ static RefPtr<ipc::SharedMemory> GetHyphDictFromParent(nsIURI* aURI,
|
||||
return shm;
|
||||
}
|
||||
|
||||
static RefPtr<ipc::SharedMemory> CopyToShmem(const CompiledData* aData) {
|
||||
static UniquePtr<base::SharedMemory> CopyToShmem(const CompiledData* aData) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
// The shm-related calls here are not expected to fail, but if they do,
|
||||
// we'll just return null (as if the resource was unavailable) and proceed
|
||||
// without hyphenation.
|
||||
uint32_t size = mapped_hyph_compiled_data_size(aData);
|
||||
RefPtr<ipc::SharedMemory> shm = MakeRefPtr<ipc::SharedMemory>();
|
||||
if (!shm->CreateFreezable(size)) {
|
||||
UniquePtr<base::SharedMemory> shm = MakeUnique<base::SharedMemory>();
|
||||
if (!shm->CreateFreezeable(size)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!shm->Map(size)) {
|
||||
return nullptr;
|
||||
}
|
||||
char* buffer = static_cast<char*>(shm->Memory());
|
||||
char* buffer = static_cast<char*>(shm->memory());
|
||||
if (!buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -121,7 +121,8 @@ static RefPtr<ipc::SharedMemory> CopyToShmem(const CompiledData* aData) {
|
||||
return shm;
|
||||
}
|
||||
|
||||
static RefPtr<ipc::SharedMemory> LoadFromURI(nsIURI* aURI, uint32_t* aLength,
|
||||
static UniquePtr<base::SharedMemory> LoadFromURI(nsIURI* aURI,
|
||||
uint32_t* aLength,
|
||||
bool aPrecompiled) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
@@ -145,14 +146,14 @@ static RefPtr<ipc::SharedMemory> LoadFromURI(nsIURI* aURI, uint32_t* aLength,
|
||||
}
|
||||
|
||||
if (aPrecompiled) {
|
||||
RefPtr<ipc::SharedMemory> shm = MakeRefPtr<ipc::SharedMemory>();
|
||||
if (!shm->CreateFreezable(available)) {
|
||||
UniquePtr<base::SharedMemory> shm = MakeUnique<base::SharedMemory>();
|
||||
if (!shm->CreateFreezeable(available)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!shm->Map(available)) {
|
||||
return nullptr;
|
||||
}
|
||||
char* buffer = static_cast<char*>(shm->Memory());
|
||||
char* buffer = static_cast<char*>(shm->memory());
|
||||
if (!buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -211,7 +212,7 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
|
||||
// compilation once per language per session.
|
||||
if (!precompiled && !XRE_IsParentProcess()) {
|
||||
uint32_t length;
|
||||
RefPtr<ipc::SharedMemory> shm = GetHyphDictFromParent(aURI, &length);
|
||||
UniquePtr<base::SharedMemory> shm = GetHyphDictFromParent(aURI, &length);
|
||||
if (shm) {
|
||||
// We don't need to validate mDict because the parent process
|
||||
// will have done so.
|
||||
@@ -245,7 +246,7 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
|
||||
UniquePtr<const CompiledData> data(mapped_hyph_compile_buffer(
|
||||
static_cast<const uint8_t*>(ptr), length, false));
|
||||
if (data) {
|
||||
RefPtr<ipc::SharedMemory> shm = CopyToShmem(data.get());
|
||||
UniquePtr<base::SharedMemory> shm = CopyToShmem(data.get());
|
||||
if (shm) {
|
||||
mDictSize = mapped_hyph_compiled_data_size(data.get());
|
||||
mDict = AsVariant(std::move(shm));
|
||||
@@ -259,14 +260,16 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
|
||||
// buffer; if we're a child, send a request to the parent for the
|
||||
// shared-memory copy (which it will load if not already available).
|
||||
if (XRE_IsParentProcess()) {
|
||||
RefPtr<ipc::SharedMemory> shm = LoadFromURI(aURI, &length, precompiled);
|
||||
UniquePtr<base::SharedMemory> shm =
|
||||
LoadFromURI(aURI, &length, precompiled);
|
||||
if (shm) {
|
||||
mDictSize = length;
|
||||
mDict = AsVariant(std::move(shm));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
RefPtr<ipc::SharedMemory> shm = GetHyphDictFromParent(aURI, &length);
|
||||
UniquePtr<base::SharedMemory> shm =
|
||||
GetHyphDictFromParent(aURI, &length);
|
||||
if (shm) {
|
||||
// We don't need to validate mDict because the parent process
|
||||
// will have done so.
|
||||
@@ -312,7 +315,7 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
|
||||
UniquePtr<const CompiledData> data(
|
||||
mapped_hyph_compile_file(path.get(), false));
|
||||
if (data) {
|
||||
RefPtr<ipc::SharedMemory> shm = CopyToShmem(data.get());
|
||||
UniquePtr<base::SharedMemory> shm = CopyToShmem(data.get());
|
||||
if (shm) {
|
||||
mDictSize = mapped_hyph_compiled_data_size(data.get());
|
||||
mDict = AsVariant(std::move(shm));
|
||||
@@ -334,7 +337,7 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
|
||||
bool nsHyphenator::IsValid() {
|
||||
return mDict.match(
|
||||
[](const void*& ptr) { return ptr != nullptr; },
|
||||
[](RefPtr<ipc::SharedMemory>& shm) { return shm != nullptr; },
|
||||
[](UniquePtr<base::SharedMemory>& shm) { return shm != nullptr; },
|
||||
[](UniquePtr<const HyphDic>& hyph) { return hyph != nullptr; });
|
||||
}
|
||||
|
||||
@@ -446,9 +449,9 @@ void nsHyphenator::HyphenateWord(const nsAString& aString, uint32_t aStart,
|
||||
static_cast<const uint8_t*>(ptr), mDictSize, utf8.BeginReading(),
|
||||
utf8.Length(), hyphenValues.Elements(), hyphenValues.Length());
|
||||
},
|
||||
[&](RefPtr<ipc::SharedMemory>& shm) {
|
||||
[&](UniquePtr<base::SharedMemory>& shm) {
|
||||
return mapped_hyph_find_hyphen_values_raw(
|
||||
static_cast<const uint8_t*>(shm->Memory()), mDictSize,
|
||||
static_cast<const uint8_t*>(shm->memory()), mDictSize,
|
||||
utf8.BeginReading(), utf8.Length(), hyphenValues.Elements(),
|
||||
hyphenValues.Length());
|
||||
},
|
||||
@@ -486,14 +489,14 @@ void nsHyphenator::HyphenateWord(const nsAString& aString, uint32_t aStart,
|
||||
}
|
||||
}
|
||||
|
||||
void nsHyphenator::CloneHandle(ipc::SharedMemory::Handle* aOutHandle,
|
||||
void nsHyphenator::CloneHandle(base::SharedMemoryHandle* aOutHandle,
|
||||
uint32_t* aOutSize) {
|
||||
// If the resource is invalid, or if we fail to share it to the child
|
||||
// process, we'll just bail out and continue without hyphenation; no need
|
||||
// for this to be a fatal error.
|
||||
if (!mDict.is<RefPtr<ipc::SharedMemory>>()) {
|
||||
if (!mDict.is<UniquePtr<base::SharedMemory>>()) {
|
||||
return;
|
||||
}
|
||||
*aOutHandle = mDict.as<RefPtr<ipc::SharedMemory>>()->CloneHandle();
|
||||
*aOutHandle = mDict.as<UniquePtr<base::SharedMemory>>()->CloneHandle();
|
||||
*aOutSize = mDictSize;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#ifndef nsHyphenator_h__
|
||||
#define nsHyphenator_h__
|
||||
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "base/shared_memory.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Variant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@@ -42,8 +41,7 @@ class nsHyphenator {
|
||||
|
||||
nsresult Hyphenate(const nsAString& aText, nsTArray<bool>& aHyphens);
|
||||
|
||||
void CloneHandle(mozilla::ipc::SharedMemory::Handle* aOutHandle,
|
||||
uint32_t* aOutSize);
|
||||
void CloneHandle(base::SharedMemoryHandle* aOutHandle, uint32_t* aOutSize);
|
||||
|
||||
private:
|
||||
~nsHyphenator() = default;
|
||||
@@ -52,7 +50,7 @@ class nsHyphenator {
|
||||
nsTArray<bool>& aHyphens);
|
||||
|
||||
mozilla::Variant<const void*, // raw pointer to uncompressed omnijar data
|
||||
RefPtr<mozilla::ipc::SharedMemory>, // shmem block
|
||||
mozilla::UniquePtr<base::SharedMemory>, // shmem block
|
||||
mozilla::UniquePtr<const HyphDic> // loaded by mapped_hyph
|
||||
>
|
||||
mDict;
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
|
||||
%{C++
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
}
|
||||
namespace ipc {
|
||||
class FileDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
// Define Contractid and CID
|
||||
@@ -27,7 +29,7 @@ class ContentParent;
|
||||
%}
|
||||
|
||||
[ptr] native ContentParent(mozilla::dom::ContentParent);
|
||||
[ref] native SharedMemoryHandle(mozilla::ipc::SharedMemoryHandle);
|
||||
[ref] native FileDescriptor(mozilla::ipc::FileDescriptor);
|
||||
native MallocSizeOf(mozilla::MallocSizeOf);
|
||||
|
||||
[scriptable, builtinclass, uuid(D85A17C2-AA7C-11d2-9B8C-00805F8A16D9)]
|
||||
@@ -104,6 +106,6 @@ interface nsIStringBundleService : nsISupports
|
||||
[notxpcom, nostdcall] void sendContentBundles(in ContentParent aContentParent);
|
||||
|
||||
[notxpcom, nostdcall] void registerContentBundle(in ACString aBundleURL,
|
||||
[const] in SharedMemoryHandle aMapHandle,
|
||||
[const] in FileDescriptor aMapFile,
|
||||
in size_t aMapSize);
|
||||
};
|
||||
|
||||
@@ -209,8 +209,7 @@ class SharedStringBundle final : public nsStringBundleBase {
|
||||
* called in child processes, for bundles initially created in the parent
|
||||
* process.
|
||||
*/
|
||||
void SetMapFile(const mozilla::ipc::SharedMemoryHandle& aHandle,
|
||||
size_t aSize);
|
||||
void SetMapFile(const FileDescriptor& aFile, size_t aSize);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(SHAREDSTRINGBUNDLE_IID)
|
||||
@@ -223,16 +222,16 @@ class SharedStringBundle final : public nsStringBundleBase {
|
||||
* parent process, and may be used to send shared string bundles to child
|
||||
* processes.
|
||||
*/
|
||||
mozilla::ipc::SharedMemoryHandle CloneHandle() const {
|
||||
FileDescriptor CloneFileDescriptor() const {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
if (mMapHandle.isSome()) {
|
||||
return mozilla::ipc::SharedMemory::CloneHandle(mMapHandle.ref());
|
||||
if (mMapFile.isSome()) {
|
||||
return mMapFile.ref();
|
||||
}
|
||||
return mStringMap->CloneHandle();
|
||||
return mStringMap->CloneFileDescriptor();
|
||||
}
|
||||
|
||||
size_t MapSize() const {
|
||||
if (mMapHandle.isSome()) {
|
||||
if (mMapFile.isSome()) {
|
||||
return mMapSize;
|
||||
}
|
||||
if (mStringMap) {
|
||||
@@ -241,14 +240,14 @@ class SharedStringBundle final : public nsStringBundleBase {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Initialized() const { return mStringMap || mMapHandle.isSome(); }
|
||||
bool Initialized() const { return mStringMap || mMapFile.isSome(); }
|
||||
|
||||
StringBundleDescriptor GetDescriptor() const {
|
||||
MOZ_ASSERT(Initialized());
|
||||
|
||||
StringBundleDescriptor descriptor;
|
||||
descriptor.bundleURL() = BundleURL();
|
||||
descriptor.mapHandle() = CloneHandle();
|
||||
descriptor.mapFile() = CloneFileDescriptor();
|
||||
descriptor.mapSize() = MapSize();
|
||||
return descriptor;
|
||||
}
|
||||
@@ -274,7 +273,7 @@ class SharedStringBundle final : public nsStringBundleBase {
|
||||
private:
|
||||
RefPtr<SharedStringMap> mStringMap;
|
||||
|
||||
Maybe<mozilla::ipc::SharedMemoryHandle> mMapHandle;
|
||||
Maybe<FileDescriptor> mMapFile;
|
||||
size_t mMapSize;
|
||||
};
|
||||
|
||||
@@ -522,9 +521,9 @@ nsresult nsStringBundle::LoadProperties() {
|
||||
nsresult SharedStringBundle::LoadProperties() {
|
||||
if (mStringMap) return NS_OK;
|
||||
|
||||
if (mMapHandle.isSome()) {
|
||||
mStringMap = new SharedStringMap(mMapHandle.ref(), mMapSize);
|
||||
mMapHandle.reset();
|
||||
if (mMapFile.isSome()) {
|
||||
mStringMap = new SharedStringMap(mMapFile.ref(), mMapSize);
|
||||
mMapFile.reset();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -577,11 +576,10 @@ nsresult SharedStringBundle::LoadProperties() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void SharedStringBundle::SetMapFile(
|
||||
const mozilla::ipc::SharedMemoryHandle& aHandle, size_t aSize) {
|
||||
void SharedStringBundle::SetMapFile(const FileDescriptor& aFile, size_t aSize) {
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
mStringMap = nullptr;
|
||||
mMapHandle.emplace(mozilla::ipc::SharedMemory::CloneHandle(aHandle));
|
||||
mMapFile.emplace(aFile);
|
||||
mMapSize = aSize;
|
||||
}
|
||||
|
||||
@@ -829,8 +827,8 @@ void nsStringBundleService::SendContentBundles(ContentParent* aContentParent) {
|
||||
}
|
||||
|
||||
void nsStringBundleService::RegisterContentBundle(
|
||||
const nsACString& aBundleURL,
|
||||
const mozilla::ipc::SharedMemoryHandle& aMapHandle, size_t aMapSize) {
|
||||
const nsACString& aBundleURL, const FileDescriptor& aMapFile,
|
||||
size_t aMapSize) {
|
||||
RefPtr<StringBundleProxy> proxy;
|
||||
|
||||
bundleCacheEntry_t* cacheEntry = mBundleMap.Get(aBundleURL);
|
||||
@@ -848,7 +846,7 @@ void nsStringBundleService::RegisterContentBundle(
|
||||
|
||||
auto bundle = MakeBundleRefPtr<SharedStringBundle>(
|
||||
PromiseFlatCString(aBundleURL).get());
|
||||
bundle->SetMapFile(aMapHandle, aMapSize);
|
||||
bundle->SetMapFile(aMapFile, aMapSize);
|
||||
|
||||
if (proxy) {
|
||||
proxy->Retarget(bundle);
|
||||
|
||||
@@ -47,6 +47,7 @@ if CONFIG["TARGET_KERNEL"] == "WINNT":
|
||||
"src/base/object_watcher.cc",
|
||||
"src/base/platform_thread_win.cc",
|
||||
"src/base/process_util_win.cc",
|
||||
"src/base/shared_memory_win.cc",
|
||||
"src/base/sys_string_conversions_win.cc",
|
||||
"src/base/thread_local_win.cc",
|
||||
"src/base/time_win.cc",
|
||||
@@ -66,6 +67,7 @@ if CONFIG["TARGET_KERNEL"] != "WINNT":
|
||||
"src/base/message_pump_libevent.cc",
|
||||
"src/base/platform_thread_posix.cc",
|
||||
"src/base/process_util_posix.cc",
|
||||
"src/base/shared_memory_posix.cc",
|
||||
"src/base/string16.cc",
|
||||
"src/base/thread_local_posix.cc",
|
||||
"src/base/waitable_event_posix.cc",
|
||||
|
||||
197
ipc/chromium/src/base/shared_memory.h
Normal file
197
ipc/chromium/src/base/shared_memory.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_SHARED_MEMORY_H_
|
||||
#define BASE_SHARED_MEMORY_H_
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
# include <sys/types.h>
|
||||
# include <semaphore.h>
|
||||
#endif
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/process.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// SharedMemoryHandle is a platform specific type which represents
|
||||
// the underlying OS handle to a shared memory segment.
|
||||
typedef mozilla::UniqueFileHandle SharedMemoryHandle;
|
||||
|
||||
// Platform abstraction for shared memory. Provides a C++ wrapper
|
||||
// around the OS primitive for a memory mapped file.
|
||||
class SharedMemory {
|
||||
public:
|
||||
// Create a new SharedMemory object.
|
||||
SharedMemory() = default;
|
||||
|
||||
// Create a new SharedMemory object from an existing, open
|
||||
// shared memory file.
|
||||
SharedMemory(SharedMemoryHandle init_handle, bool read_only)
|
||||
: SharedMemory() {
|
||||
SetHandle(std::move(init_handle), read_only);
|
||||
}
|
||||
|
||||
// Move constructor; transfers ownership.
|
||||
SharedMemory(SharedMemory&& other) = default;
|
||||
|
||||
// Destructor. Will close any open files.
|
||||
~SharedMemory();
|
||||
|
||||
// Initialize a new SharedMemory object from an existing, open
|
||||
// shared memory file.
|
||||
bool SetHandle(SharedMemoryHandle handle, bool read_only);
|
||||
|
||||
// Return true iff the given handle is valid (i.e. not the distingished
|
||||
// invalid value; NULL for a HANDLE and -1 for a file descriptor)
|
||||
static bool IsHandleValid(const SharedMemoryHandle& handle);
|
||||
|
||||
// IsHandleValid applied to this object's handle.
|
||||
bool IsValid() const { return static_cast<bool>(mapped_file_); }
|
||||
|
||||
// Return invalid handle (see comment above for exact definition).
|
||||
static SharedMemoryHandle NULLHandle();
|
||||
|
||||
// Creates a shared memory segment.
|
||||
// Returns true on success, false on failure.
|
||||
bool Create(size_t size) { return CreateInternal(size, false); }
|
||||
|
||||
// Creates a shared memory segment that supports the Freeze()
|
||||
// method; see below. (Warning: creating freezeable shared memory
|
||||
// within a sandboxed process isn't possible on some platforms.)
|
||||
// Returns true on success, false on failure.
|
||||
bool CreateFreezeable(size_t size) { return CreateInternal(size, true); }
|
||||
|
||||
// Maps the shared memory into the caller's address space.
|
||||
// Returns true on success, false otherwise. The memory address
|
||||
// is accessed via the memory() accessor.
|
||||
//
|
||||
// If the specified fixed address is not null, it is the address that the
|
||||
// shared memory must be mapped at. Returns false if the shared memory
|
||||
// could not be mapped at that address.
|
||||
bool Map(size_t bytes, void* fixed_address = nullptr);
|
||||
|
||||
// Unmaps the shared memory from the caller's address space.
|
||||
void Unmap() { memory_ = nullptr; }
|
||||
|
||||
// Get the size of the opened shared memory backing file.
|
||||
// Note: This size is only available to the creator of the
|
||||
// shared memory, and not to those that opened shared memory
|
||||
// created externally.
|
||||
// Returns 0 if not opened or unknown.
|
||||
size_t max_size() const { return max_size_; }
|
||||
|
||||
// Gets a pointer to the opened memory space if it has been
|
||||
// Mapped via Map(). Returns NULL if it is not mapped.
|
||||
void* memory() const { return memory_.get(); }
|
||||
|
||||
// Extracts the underlying file handle, returning a RAII type.
|
||||
// If `unmap_view` is true, this unmaps the memory as a side-effect (and
|
||||
// cleans up any OS-specific resources).
|
||||
mozilla::UniqueFileHandle TakeHandle(bool unmap_view = true) {
|
||||
mozilla::UniqueFileHandle handle = std::move(mapped_file_);
|
||||
Close(unmap_view);
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Creates a copy of the underlying file handle, returning a RAII type.
|
||||
// This operation may fail, in which case the returned file handle will be
|
||||
// invalid.
|
||||
mozilla::UniqueFileHandle CloneHandle();
|
||||
|
||||
// Make the shared memory object read-only, such that it cannot be
|
||||
// written even if it's sent to an untrusted process. If it was
|
||||
// mapped in this process, it will be unmapped. The object must
|
||||
// have been created with CreateFreezeable(), and must not have
|
||||
// already been shared to another process.
|
||||
//
|
||||
// (See bug 1479960 comment #0 for OS-specific implementation
|
||||
// details.)
|
||||
[[nodiscard]] bool Freeze() {
|
||||
Unmap();
|
||||
return ReadOnlyCopy(this);
|
||||
}
|
||||
|
||||
// Similar to Freeze(), but assigns the read-only capability to
|
||||
// another SharedMemory object and leaves this object's mapping in
|
||||
// place and writeable. This can be used to broadcast data to
|
||||
// several untrusted readers without copying.
|
||||
//
|
||||
// The other constraints of Freeze() still apply: this object closes
|
||||
// its handle (as if by `Close(false)`), it cannot have been
|
||||
// previously shared, and the read-only handle cannot be used to
|
||||
// write the memory even by a malicious process.
|
||||
//
|
||||
// (The out parameter can currently be the same as `this` if and
|
||||
// only if the memory was unmapped, but this is an implementation
|
||||
// detail and shouldn't be relied on; for that use case Freeze()
|
||||
// should be used instead.)
|
||||
[[nodiscard]] bool ReadOnlyCopy(SharedMemory* ro_out);
|
||||
|
||||
// Closes the open shared memory segment.
|
||||
// It is safe to call Close repeatedly.
|
||||
void Close(bool unmap_view = true);
|
||||
|
||||
// Returns a page-aligned address at which the given number of bytes could
|
||||
// probably be mapped. Returns NULL on error or if there is insufficient
|
||||
// contiguous address space to map the required number of pages.
|
||||
//
|
||||
// Note that there is no guarantee that the given address space will actually
|
||||
// be free by the time this function returns, since another thread might map
|
||||
// something there in the meantime.
|
||||
static void* FindFreeAddressSpace(size_t size);
|
||||
|
||||
#ifdef XP_UNIX
|
||||
// If named POSIX shm is being used, append the prefix (including
|
||||
// the leading '/') that would be used by a process with the given
|
||||
// pid to the given string and return true. If not, return false.
|
||||
// (This is public so that the Linux sandboxing code can use it.)
|
||||
static bool AppendPosixShmPrefix(std::string* str, pid_t pid);
|
||||
// Similar, but simply returns whether POSIX shm is in use.
|
||||
static bool UsingPosixShm();
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool CreateInternal(size_t size, bool freezeable);
|
||||
|
||||
// Unmapping shared memory requires the mapped size on Unix but not
|
||||
// Windows; this encapsulates that difference.
|
||||
struct MappingDeleter {
|
||||
#ifdef XP_UNIX
|
||||
// A default-constructed deleter must be used only with nullptr
|
||||
// (to allow default-constructing UniqueMapping). A deleter with
|
||||
// a size must be used at most once.
|
||||
size_t mapped_size_ = 0;
|
||||
explicit MappingDeleter(size_t size) : mapped_size_(size) {}
|
||||
#endif
|
||||
MappingDeleter() = default;
|
||||
void operator()(void* ptr);
|
||||
};
|
||||
using UniqueMapping = mozilla::UniquePtr<void, MappingDeleter>;
|
||||
|
||||
UniqueMapping memory_;
|
||||
size_t max_size_ = 0;
|
||||
mozilla::UniqueFileHandle mapped_file_;
|
||||
#if defined(XP_WIN)
|
||||
// If true indicates this came from an external source so needs extra checks
|
||||
// before being mapped.
|
||||
bool external_section_ = false;
|
||||
#elif !defined(ANDROID)
|
||||
mozilla::UniqueFileHandle frozen_file_;
|
||||
bool is_memfd_ = false;
|
||||
#endif
|
||||
bool read_only_ = false;
|
||||
bool freezeable_ = false;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(SharedMemory);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SHARED_MEMORY_H_
|
||||
563
ipc/chromium/src/base/shared_memory_posix.cc
Normal file
563
ipc/chromium/src/base/shared_memory_posix.cc
Normal file
@@ -0,0 +1,563 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
# include "mozilla/Ashmem.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_LINUX
|
||||
# include "linux_memfd_defs.h"
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
# include "mozilla/WidgetUtilsGtk.h"
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
# include <sys/capsicum.h>
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_VALGRIND
|
||||
# include <valgrind/valgrind.h>
|
||||
#endif
|
||||
|
||||
#include "base/eintr_wrapper.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/string_util.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/ProfilerThreadSleep.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "prenv.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
void SharedMemory::MappingDeleter::operator()(void* ptr) {
|
||||
// Check that this isn't a default-constructed deleter. (`munmap`
|
||||
// is specified to fail with `EINVAL` if the length is 0, so this
|
||||
// assertion isn't load-bearing.)
|
||||
DCHECK(mapped_size_ != 0);
|
||||
munmap(ptr, mapped_size_);
|
||||
// Guard against multiple calls of the same deleter, which shouldn't
|
||||
// happen (but could, if `UniquePtr::reset` were used). Calling
|
||||
// `munmap` with an incorrect non-zero length would be bad.
|
||||
mapped_size_ = 0;
|
||||
}
|
||||
|
||||
SharedMemory::~SharedMemory() {
|
||||
// This is almost equal to the default destructor, except for the
|
||||
// warning message about unfrozen freezable memory.
|
||||
Close();
|
||||
}
|
||||
|
||||
bool SharedMemory::SetHandle(SharedMemoryHandle handle, bool read_only) {
|
||||
DCHECK(!mapped_file_);
|
||||
#ifndef ANDROID
|
||||
DCHECK(!frozen_file_);
|
||||
#endif
|
||||
|
||||
freezeable_ = false;
|
||||
mapped_file_ = std::move(handle);
|
||||
read_only_ = read_only;
|
||||
// is_memfd_ only matters for freezing, which isn't possible
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
|
||||
return handle != nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
SharedMemoryHandle SharedMemory::NULLHandle() { return nullptr; }
|
||||
|
||||
// static
|
||||
bool SharedMemory::UsingPosixShm() {
|
||||
// Undocumented feature of AppendPosixShmPrefix to reduce code
|
||||
// duplication: if the string pointer is null, it's ignored.
|
||||
return AppendPosixShmPrefix(nullptr, 0);
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
// Android has its own shared memory API, ashmem. It doesn't support
|
||||
// POSIX shm_open, and the memfd support (see below) also doesn't work
|
||||
// because its SELinux policy prevents the procfs operations we'd use
|
||||
// (see bug 1670277 for more details).
|
||||
|
||||
// static
|
||||
bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SharedMemory::CreateInternal(size_t size, bool freezeable) {
|
||||
read_only_ = false;
|
||||
|
||||
DCHECK(size > 0);
|
||||
DCHECK(!mapped_file_);
|
||||
|
||||
int fd = mozilla::android::ashmem_create(nullptr, size);
|
||||
if (fd < 0) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
mapped_file_.reset(fd);
|
||||
max_size_ = size;
|
||||
freezeable_ = freezeable;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
|
||||
DCHECK(mapped_file_);
|
||||
DCHECK(!read_only_);
|
||||
CHECK(freezeable_);
|
||||
|
||||
if (ro_out == this) {
|
||||
DCHECK(!memory_);
|
||||
}
|
||||
|
||||
if (mozilla::android::ashmem_setProt(mapped_file_.get(), PROT_READ) != 0) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to set ashmem read-only: "
|
||||
<< strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::UniqueFileHandle ro_file = std::move(mapped_file_);
|
||||
|
||||
freezeable_ = false;
|
||||
ro_out->Close();
|
||||
ro_out->mapped_file_ = std::move(ro_file);
|
||||
ro_out->max_size_ = max_size_;
|
||||
ro_out->read_only_ = true;
|
||||
ro_out->freezeable_ = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#else // not Android
|
||||
|
||||
// memfd_create is a nonstandard interface for creating anonymous
|
||||
// shared memory accessible as a file descriptor but not tied to any
|
||||
// filesystem. It first appeared in Linux 3.17, and was adopted by
|
||||
// FreeBSD in version 13.
|
||||
|
||||
# if !defined(HAVE_MEMFD_CREATE) && defined(XP_LINUX) && \
|
||||
defined(SYS_memfd_create)
|
||||
|
||||
// Older libc versions (e.g., glibc before 2.27) don't have the
|
||||
// wrapper, but we can supply our own; see `linux_memfd_defs.h`.
|
||||
|
||||
static int memfd_create(const char* name, unsigned int flags) {
|
||||
return syscall(SYS_memfd_create, name, flags);
|
||||
}
|
||||
|
||||
# define HAVE_MEMFD_CREATE 1
|
||||
# endif
|
||||
|
||||
// memfd supports having "seals" applied to the file, to prevent
|
||||
// various types of changes (which apply to all fds referencing the
|
||||
// file). Unfortunately, we can't rely on F_SEAL_WRITE to implement
|
||||
// Freeze(); see the comments in ReadOnlyCopy() below.
|
||||
//
|
||||
// Instead, to prevent a child process from regaining write access to
|
||||
// a read-only copy, the OS must also provide a way to remove write
|
||||
// permissions at the file descriptor level. This next section
|
||||
// attempts to accomplish that.
|
||||
|
||||
# ifdef HAVE_MEMFD_CREATE
|
||||
# ifdef XP_LINUX
|
||||
# define USE_MEMFD_CREATE 1
|
||||
|
||||
// To create a read-only duplicate of an fd, we can use procfs; the
|
||||
// same operation could restore write access, but sandboxing prevents
|
||||
// child processes from accessing /proc.
|
||||
//
|
||||
// (Note: if this ever changes to not use /proc, also reconsider how
|
||||
// and if HaveMemfd should check whether this works.)
|
||||
|
||||
static int DupReadOnly(int fd) {
|
||||
std::string path = StringPrintf("/proc/self/fd/%d", fd);
|
||||
// procfs opens probably won't EINTR, but checking for it can't hurt
|
||||
return HANDLE_EINTR(open(path.c_str(), O_RDONLY | O_CLOEXEC));
|
||||
}
|
||||
|
||||
# elif defined(__FreeBSD__)
|
||||
# define USE_MEMFD_CREATE 1
|
||||
|
||||
// FreeBSD's Capsicum framework allows irrevocably restricting the
|
||||
// operations permitted on a file descriptor.
|
||||
|
||||
static int DupReadOnly(int fd) {
|
||||
int rofd = dup(fd);
|
||||
if (rofd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cap_rights_t rights;
|
||||
cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R);
|
||||
if (cap_rights_limit(rofd, &rights) < 0) {
|
||||
int err = errno;
|
||||
close(rofd);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rofd;
|
||||
}
|
||||
|
||||
# else // unhandled OS
|
||||
# warning "OS has memfd_create but no DupReadOnly implementation"
|
||||
# endif // OS selection
|
||||
# endif // HAVE_MEMFD_CREATE
|
||||
|
||||
// Runtime detection for memfd support.
|
||||
static bool HaveMemfd() {
|
||||
# ifdef USE_MEMFD_CREATE
|
||||
static const bool kHave = [] {
|
||||
mozilla::UniqueFileHandle fd(
|
||||
memfd_create("mozilla-ipc-test", MFD_CLOEXEC | MFD_ALLOW_SEALING));
|
||||
if (!fd) {
|
||||
DCHECK_EQ(errno, ENOSYS);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify that DupReadOnly works; on Linux it's known to fail if:
|
||||
//
|
||||
// * SELinux assigns the memfd a type for which this process's
|
||||
// domain doesn't have "open" permission; this is always the
|
||||
// case on Android but could occur on desktop as well
|
||||
//
|
||||
// * /proc (used by the DupReadOnly implementation) isn't mounted,
|
||||
// which is a configuration that the Tor Browser project is
|
||||
// interested in as a way to reduce fingerprinting risk
|
||||
//
|
||||
// Sandboxed processes on Linux also can't use it if sandboxing
|
||||
// has already been started, but that's expected. It should be
|
||||
// safe for sandboxed child processes to use memfd even if an
|
||||
// unsandboxed process couldn't freeze them, because freezing
|
||||
// isn't allowed (or meaningful) for memory created by another
|
||||
// process.
|
||||
|
||||
if (!PR_GetEnv("MOZ_SANDBOXED")) {
|
||||
mozilla::UniqueFileHandle rofd(DupReadOnly(fd.get()));
|
||||
if (!rofd) {
|
||||
CHROMIUM_LOG(WARNING) << "read-only dup failed (" << strerror(errno)
|
||||
<< "); not using memfd";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
return kHave;
|
||||
# else
|
||||
return false;
|
||||
# endif // USE_MEMFD_CREATE
|
||||
}
|
||||
|
||||
// static
|
||||
bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid) {
|
||||
if (HaveMemfd()) {
|
||||
return false;
|
||||
}
|
||||
// See also UsingPosixShm().
|
||||
if (!str) {
|
||||
return true;
|
||||
}
|
||||
*str += '/';
|
||||
# ifdef MOZ_WIDGET_GTK
|
||||
// The Snap package environment doesn't provide a private /dev/shm
|
||||
// (it's used for communication with services like PulseAudio);
|
||||
// instead AppArmor is used to restrict access to it. Anything with
|
||||
// this prefix is allowed:
|
||||
if (const char* snap = mozilla::widget::GetSnapInstanceName()) {
|
||||
StringAppendF(str, "snap.%s.", snap);
|
||||
}
|
||||
# endif // XP_LINUX
|
||||
// Hopefully the "implementation defined" name length limit is long
|
||||
// enough for this.
|
||||
StringAppendF(str, "org.mozilla.ipc.%d.", static_cast<int>(pid));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::CreateInternal(size_t size, bool freezeable) {
|
||||
read_only_ = false;
|
||||
|
||||
DCHECK(size > 0);
|
||||
DCHECK(!mapped_file_);
|
||||
DCHECK(!frozen_file_);
|
||||
|
||||
mozilla::UniqueFileHandle fd;
|
||||
mozilla::UniqueFileHandle frozen_fd;
|
||||
bool is_memfd = false;
|
||||
|
||||
# ifdef USE_MEMFD_CREATE
|
||||
if (HaveMemfd()) {
|
||||
const unsigned flags = MFD_CLOEXEC | (freezeable ? MFD_ALLOW_SEALING : 0);
|
||||
fd.reset(memfd_create("mozilla-ipc", flags));
|
||||
if (!fd) {
|
||||
// In general it's too late to fall back here -- in a sandboxed
|
||||
// child process, shm_open is already blocked. And it shouldn't
|
||||
// be necessary.
|
||||
CHROMIUM_LOG(WARNING) << "failed to create memfd: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
is_memfd = true;
|
||||
if (freezeable) {
|
||||
frozen_fd.reset(DupReadOnly(fd.get()));
|
||||
if (!frozen_fd) {
|
||||
CHROMIUM_LOG(WARNING)
|
||||
<< "failed to create read-only memfd: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
if (!fd) {
|
||||
// Generic Unix: shm_open + shm_unlink
|
||||
do {
|
||||
// The names don't need to be unique, but it saves time if they
|
||||
// usually are.
|
||||
static mozilla::Atomic<size_t> sNameCounter;
|
||||
std::string name;
|
||||
CHECK(AppendPosixShmPrefix(&name, getpid()));
|
||||
StringAppendF(&name, "%zu", sNameCounter++);
|
||||
// O_EXCL means the names being predictable shouldn't be a problem.
|
||||
fd.reset(HANDLE_EINTR(
|
||||
shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)));
|
||||
if (fd) {
|
||||
if (freezeable) {
|
||||
frozen_fd.reset(HANDLE_EINTR(shm_open(name.c_str(), O_RDONLY, 0400)));
|
||||
if (!frozen_fd) {
|
||||
int open_err = errno;
|
||||
shm_unlink(name.c_str());
|
||||
DLOG(FATAL) << "failed to re-open freezeable shm: "
|
||||
<< strerror(open_err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (shm_unlink(name.c_str()) != 0) {
|
||||
// This shouldn't happen, but if it does: assume the file is
|
||||
// in fact leaked, and bail out now while it's still 0-length.
|
||||
DLOG(FATAL) << "failed to unlink shm: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (!fd && errno == EEXIST);
|
||||
}
|
||||
|
||||
if (!fd) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::Maybe<int> fallocateError;
|
||||
# if defined(HAVE_POSIX_FALLOCATE)
|
||||
// Using posix_fallocate will ensure that there's actually space for this
|
||||
// file. Otherwise we end up with a sparse file that can give SIGBUS if we
|
||||
// run out of space while writing to it. (This doesn't apply to memfd.)
|
||||
if (!is_memfd) {
|
||||
int rv;
|
||||
// Avoid repeated interruptions of posix_fallocate by the profiler's
|
||||
// SIGPROF sampling signal. Indicating "thread sleep" here means we'll
|
||||
// get up to one interruption but not more. See bug 1658847 for more.
|
||||
// This has to be scoped outside the HANDLE_RV_EINTR retry loop.
|
||||
{
|
||||
AUTO_PROFILER_THREAD_SLEEP;
|
||||
|
||||
rv = HANDLE_RV_EINTR(
|
||||
posix_fallocate(fd.get(), 0, static_cast<off_t>(size)));
|
||||
}
|
||||
|
||||
// Some filesystems have trouble with posix_fallocate. For now, we must
|
||||
// fallback ftruncate and accept the allocation failures like we do
|
||||
// without posix_fallocate.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1618914
|
||||
if (rv != 0 && rv != EOPNOTSUPP && rv != EINVAL && rv != ENODEV) {
|
||||
CHROMIUM_LOG(WARNING)
|
||||
<< "fallocate failed to set shm size: " << strerror(rv);
|
||||
return false;
|
||||
}
|
||||
fallocateError = mozilla::Some(rv);
|
||||
}
|
||||
# endif
|
||||
|
||||
// If posix_fallocate isn't supported / relevant for this type of
|
||||
// file (either failed with an expected error, or wasn't attempted),
|
||||
// then set the size with ftruncate:
|
||||
if (fallocateError != mozilla::Some(0)) {
|
||||
int rv = HANDLE_EINTR(ftruncate(fd.get(), static_cast<off_t>(size)));
|
||||
if (rv != 0) {
|
||||
int ftruncate_errno = errno;
|
||||
if (fallocateError) {
|
||||
CHROMIUM_LOG(WARNING) << "fallocate failed to set shm size: "
|
||||
<< strerror(*fallocateError);
|
||||
}
|
||||
CHROMIUM_LOG(WARNING)
|
||||
<< "ftruncate failed to set shm size: " << strerror(ftruncate_errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mapped_file_ = std::move(fd);
|
||||
frozen_file_ = std::move(frozen_fd);
|
||||
max_size_ = size;
|
||||
freezeable_ = freezeable;
|
||||
is_memfd_ = is_memfd;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
|
||||
DCHECK(mapped_file_);
|
||||
DCHECK(!read_only_);
|
||||
CHECK(freezeable_);
|
||||
|
||||
if (ro_out == this) {
|
||||
DCHECK(!memory_);
|
||||
}
|
||||
|
||||
# ifdef USE_MEMFD_CREATE
|
||||
# ifdef MOZ_VALGRIND
|
||||
// Valgrind allows memfd_create but doesn't understand F_ADD_SEALS.
|
||||
static const bool haveSeals = RUNNING_ON_VALGRIND == 0;
|
||||
# else
|
||||
static const bool haveSeals = true;
|
||||
# endif
|
||||
static const bool useSeals = !PR_GetEnv("MOZ_SHM_NO_SEALS");
|
||||
if (is_memfd_ && haveSeals && useSeals) {
|
||||
// Seals are added to the file as defense-in-depth. The primary
|
||||
// method of access control is creating a read-only fd (using
|
||||
// procfs in this case) and requiring that sandboxes processes not
|
||||
// have access to /proc/self/fd to regain write permission; this
|
||||
// is the same as with shm_open.
|
||||
//
|
||||
// Unfortunately, F_SEAL_WRITE is unreliable: if the process
|
||||
// forked while there was a writeable mapping, it will inherit a
|
||||
// copy of the mapping, which causes the seal to fail.
|
||||
//
|
||||
// (Also, in the future we may want to split this into separate
|
||||
// classes for mappings and shared memory handles, which would
|
||||
// complicate identifying the case where `F_SEAL_WRITE` would be
|
||||
// possible even in the absence of races with fork.)
|
||||
//
|
||||
// However, Linux 5.1 added F_SEAL_FUTURE_WRITE, which prevents
|
||||
// write operations afterwards, but existing writeable mappings
|
||||
// are unaffected (similar to ashmem protection semantics).
|
||||
|
||||
const int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL;
|
||||
int sealError = EINVAL;
|
||||
|
||||
# ifdef F_SEAL_FUTURE_WRITE
|
||||
sealError =
|
||||
fcntl(mapped_file_.get(), F_ADD_SEALS, seals | F_SEAL_FUTURE_WRITE) == 0
|
||||
? 0
|
||||
: errno;
|
||||
# endif // F_SEAL_FUTURE_WRITE
|
||||
if (sealError == EINVAL) {
|
||||
sealError =
|
||||
fcntl(mapped_file_.get(), F_ADD_SEALS, seals) == 0 ? 0 : errno;
|
||||
}
|
||||
if (sealError != 0) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to seal memfd: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
# else // !USE_MEMFD_CREATE
|
||||
DCHECK(!is_memfd_);
|
||||
# endif
|
||||
|
||||
DCHECK(frozen_file_);
|
||||
DCHECK(mapped_file_);
|
||||
mapped_file_ = nullptr;
|
||||
mozilla::UniqueFileHandle ro_file = std::move(frozen_file_);
|
||||
|
||||
DCHECK(ro_file);
|
||||
freezeable_ = false;
|
||||
ro_out->Close();
|
||||
ro_out->mapped_file_ = std::move(ro_file);
|
||||
ro_out->max_size_ = max_size_;
|
||||
ro_out->read_only_ = true;
|
||||
ro_out->freezeable_ = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // not Android
|
||||
|
||||
#ifndef MAP_NORESERVE
|
||||
# define MAP_NORESERVE 0
|
||||
#endif
|
||||
|
||||
bool SharedMemory::Map(size_t bytes, void* fixed_address) {
|
||||
if (!mapped_file_) {
|
||||
return false;
|
||||
}
|
||||
DCHECK(!memory_);
|
||||
|
||||
// Don't use MAP_FIXED when a fixed_address was specified, since that can
|
||||
// replace pages that are alread mapped at that address.
|
||||
void* mem =
|
||||
mmap(fixed_address, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
|
||||
MAP_SHARED, mapped_file_.get(), 0);
|
||||
|
||||
if (mem == MAP_FAILED) {
|
||||
CHROMIUM_LOG(WARNING) << "Call to mmap failed: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fixed_address && mem != fixed_address) {
|
||||
bool munmap_succeeded = munmap(mem, bytes) == 0;
|
||||
DCHECK(munmap_succeeded) << "Call to munmap failed, errno=" << errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
memory_ = UniqueMapping(mem, MappingDeleter(bytes));
|
||||
return true;
|
||||
}
|
||||
|
||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
||||
void* memory = mmap(nullptr, size, PROT_NONE,
|
||||
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
|
||||
if (memory == MAP_FAILED) {
|
||||
return nullptr;
|
||||
}
|
||||
munmap(memory, size);
|
||||
return memory;
|
||||
}
|
||||
|
||||
SharedMemoryHandle SharedMemory::CloneHandle() {
|
||||
freezeable_ = false;
|
||||
const int new_fd = dup(mapped_file_.get());
|
||||
if (new_fd < 0) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to duplicate file descriptor: "
|
||||
<< strerror(errno);
|
||||
return nullptr;
|
||||
}
|
||||
return mozilla::UniqueFileHandle(new_fd);
|
||||
}
|
||||
void SharedMemory::Close(bool unmap_view) {
|
||||
if (unmap_view) {
|
||||
Unmap();
|
||||
}
|
||||
|
||||
mapped_file_ = nullptr;
|
||||
#ifndef ANDROID
|
||||
if (frozen_file_) {
|
||||
CHROMIUM_LOG(WARNING) << "freezeable shared memory was never frozen";
|
||||
frozen_file_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
266
ipc/chromium/src/base/shared_memory_win.cc
Normal file
266
ipc/chromium/src/base/shared_memory_win.cc
Normal file
@@ -0,0 +1,266 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/win_util.h"
|
||||
#include "base/string_util.h"
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/RandomNum.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsString.h"
|
||||
#ifdef MOZ_MEMORY
|
||||
# include "mozmemory_utils.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
// NtQuerySection is an internal (but believed to be stable) API and the
|
||||
// structures it uses are defined in nt_internals.h.
|
||||
// So we have to define them ourselves.
|
||||
typedef enum _SECTION_INFORMATION_CLASS {
|
||||
SectionBasicInformation,
|
||||
} SECTION_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _SECTION_BASIC_INFORMATION {
|
||||
PVOID BaseAddress;
|
||||
ULONG Attributes;
|
||||
LARGE_INTEGER Size;
|
||||
} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
|
||||
|
||||
typedef ULONG(__stdcall* NtQuerySectionType)(
|
||||
HANDLE SectionHandle, SECTION_INFORMATION_CLASS SectionInformationClass,
|
||||
PVOID SectionInformation, ULONG SectionInformationLength,
|
||||
PULONG ResultLength);
|
||||
|
||||
// Checks if the section object is safe to map. At the moment this just means
|
||||
// it's not an image section.
|
||||
bool IsSectionSafeToMap(HANDLE handle) {
|
||||
static NtQuerySectionType nt_query_section_func =
|
||||
reinterpret_cast<NtQuerySectionType>(
|
||||
::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
|
||||
DCHECK(nt_query_section_func);
|
||||
|
||||
// The handle must have SECTION_QUERY access for this to succeed.
|
||||
SECTION_BASIC_INFORMATION basic_information = {};
|
||||
ULONG status =
|
||||
nt_query_section_func(handle, SectionBasicInformation, &basic_information,
|
||||
sizeof(basic_information), nullptr);
|
||||
if (status) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace base {
|
||||
|
||||
void SharedMemory::MappingDeleter::operator()(void* ptr) {
|
||||
UnmapViewOfFile(ptr);
|
||||
}
|
||||
|
||||
SharedMemory::~SharedMemory() = default;
|
||||
|
||||
bool SharedMemory::SetHandle(SharedMemoryHandle handle, bool read_only) {
|
||||
DCHECK(!mapped_file_);
|
||||
|
||||
external_section_ = true;
|
||||
freezeable_ = false; // just in case
|
||||
mapped_file_ = std::move(handle);
|
||||
read_only_ = read_only;
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
|
||||
return handle != nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
SharedMemoryHandle SharedMemory::NULLHandle() { return nullptr; }
|
||||
|
||||
// Wrapper around CreateFileMappingW for pagefile-backed regions. When out of
|
||||
// memory, may attempt to stall and retry rather than returning immediately, in
|
||||
// hopes that the page file is about to be expanded by Windows. (bug 1822383,
|
||||
// bug 1716727)
|
||||
//
|
||||
// This method is largely a copy of the MozVirtualAlloc method from
|
||||
// mozjemalloc.cpp, which implements this strategy for VirtualAlloc calls,
|
||||
// except re-purposed to handle CreateFileMapping.
|
||||
static HANDLE MozCreateFileMappingW(
|
||||
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect,
|
||||
DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName) {
|
||||
#ifdef MOZ_MEMORY
|
||||
constexpr auto IsOOMError = [] {
|
||||
return ::GetLastError() == ERROR_COMMITMENT_LIMIT;
|
||||
};
|
||||
|
||||
{
|
||||
HANDLE handle = ::CreateFileMappingW(
|
||||
INVALID_HANDLE_VALUE, lpFileMappingAttributes, flProtect,
|
||||
dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
|
||||
if (MOZ_LIKELY(handle)) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(handle != INVALID_HANDLE_VALUE,
|
||||
"::CreateFileMapping should return NULL, not "
|
||||
"INVALID_HANDLE_VALUE, on failure");
|
||||
return handle;
|
||||
}
|
||||
|
||||
// We can't do anything for errors other than OOM.
|
||||
if (!IsOOMError()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Retry as many times as desired (possibly zero).
|
||||
const mozilla::StallSpecs stallSpecs = mozilla::GetAllocatorStallSpecs();
|
||||
|
||||
const auto ret =
|
||||
stallSpecs.StallAndRetry(&::Sleep, [&]() -> std::optional<HANDLE> {
|
||||
HANDLE handle = ::CreateFileMappingW(
|
||||
INVALID_HANDLE_VALUE, lpFileMappingAttributes, flProtect,
|
||||
dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
|
||||
|
||||
if (handle) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(handle != INVALID_HANDLE_VALUE,
|
||||
"::CreateFileMapping should return NULL, not "
|
||||
"INVALID_HANDLE_VALUE, on failure");
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Failure for some reason other than OOM.
|
||||
if (!IsOOMError()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
return ret.value_or(nullptr);
|
||||
#else
|
||||
return ::CreateFileMappingW(INVALID_HANDLE_VALUE, lpFileMappingAttributes,
|
||||
flProtect, dwMaximumSizeHigh, dwMaximumSizeLow,
|
||||
lpName);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SharedMemory::CreateInternal(size_t size, bool freezeable) {
|
||||
DCHECK(!mapped_file_);
|
||||
read_only_ = false;
|
||||
|
||||
// If the shared memory object has no DACL, any process can
|
||||
// duplicate its handles with any access rights; e.g., re-add write
|
||||
// access to a read-only handle. To prevent that, we give it an
|
||||
// empty DACL, so that no process can do that.
|
||||
SECURITY_ATTRIBUTES sa, *psa = nullptr;
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
ACL dacl;
|
||||
|
||||
if (freezeable) {
|
||||
psa = &sa;
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
sa.bInheritHandle = FALSE;
|
||||
|
||||
if (NS_WARN_IF(!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) ||
|
||||
NS_WARN_IF(
|
||||
!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) ||
|
||||
NS_WARN_IF(!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mapped_file_.reset(MozCreateFileMappingW(psa, PAGE_READWRITE, 0,
|
||||
static_cast<DWORD>(size), nullptr));
|
||||
if (!mapped_file_) return false;
|
||||
|
||||
max_size_ = size;
|
||||
freezeable_ = freezeable;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
|
||||
DCHECK(!read_only_);
|
||||
CHECK(freezeable_);
|
||||
|
||||
if (ro_out == this) {
|
||||
DCHECK(!memory_);
|
||||
}
|
||||
|
||||
HANDLE ro_handle;
|
||||
if (!::DuplicateHandle(GetCurrentProcess(), mapped_file_.release(),
|
||||
GetCurrentProcess(), &ro_handle,
|
||||
GENERIC_READ | FILE_MAP_READ, false,
|
||||
DUPLICATE_CLOSE_SOURCE)) {
|
||||
// DUPLICATE_CLOSE_SOURCE applies even if there is an error.
|
||||
return false;
|
||||
}
|
||||
|
||||
freezeable_ = false;
|
||||
|
||||
ro_out->Close();
|
||||
ro_out->mapped_file_.reset(ro_handle);
|
||||
ro_out->max_size_ = max_size_;
|
||||
ro_out->read_only_ = true;
|
||||
ro_out->freezeable_ = false;
|
||||
ro_out->external_section_ = external_section_;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::Map(size_t bytes, void* fixed_address) {
|
||||
if (!mapped_file_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (external_section_ && !IsSectionSafeToMap(mapped_file_.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void* mem = MapViewOfFileEx(
|
||||
mapped_file_.get(),
|
||||
read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, bytes,
|
||||
fixed_address);
|
||||
if (mem) {
|
||||
MOZ_ASSERT(!fixed_address || mem == fixed_address,
|
||||
"MapViewOfFileEx returned an expected address");
|
||||
memory_.reset(mem);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
||||
void* memory = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
if (memory) {
|
||||
VirtualFree(memory, 0, MEM_RELEASE);
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
SharedMemoryHandle SharedMemory::CloneHandle() {
|
||||
freezeable_ = false;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
if (DuplicateHandle(GetCurrentProcess(), mapped_file_.get(),
|
||||
GetCurrentProcess(), &handle, 0, false,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
return SharedMemoryHandle(handle);
|
||||
}
|
||||
NS_WARNING("DuplicateHandle Failed!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SharedMemory::Close(bool unmap_view) {
|
||||
if (unmap_view) {
|
||||
Unmap();
|
||||
}
|
||||
|
||||
mapped_file_ = nullptr;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "mozilla/ipc/BigBuffer.h"
|
||||
|
||||
#include "chrome/common/ipc_message_utils.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
|
||||
@@ -32,9 +32,8 @@ void IdleSchedulerChild::Init(IdlePeriodState* aIdlePeriodState) {
|
||||
auto resolve =
|
||||
[&](std::tuple<mozilla::Maybe<SharedMemoryHandle>, uint32_t>&& aResult) {
|
||||
if (std::get<0>(aResult)) {
|
||||
mActiveCounter->SetHandle(std::move(*std::get<0>(aResult)),
|
||||
SharedMemory::RightsReadWrite);
|
||||
mActiveCounter->Map(sizeof(int32_t));
|
||||
mActiveCounter.SetHandle(std::move(*std::get<0>(aResult)), false);
|
||||
mActiveCounter.Map(sizeof(int32_t));
|
||||
mChildId = std::get<1>(aResult);
|
||||
if (mChildId && mIdlePeriodState && mIdlePeriodState->IsActive()) {
|
||||
SetActive();
|
||||
@@ -54,23 +53,23 @@ IPCResult IdleSchedulerChild::RecvIdleTime(uint64_t aId, TimeDuration aBudget) {
|
||||
}
|
||||
|
||||
void IdleSchedulerChild::SetActive() {
|
||||
if (mChildId && CanSend() && mActiveCounter->Memory()) {
|
||||
if (mChildId && CanSend() && mActiveCounter.memory()) {
|
||||
++(static_cast<Atomic<int32_t>*>(
|
||||
mActiveCounter->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]);
|
||||
++(static_cast<Atomic<int32_t>*>(mActiveCounter->Memory())[mChildId]);
|
||||
mActiveCounter.memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]);
|
||||
++(static_cast<Atomic<int32_t>*>(mActiveCounter.memory())[mChildId]);
|
||||
}
|
||||
}
|
||||
|
||||
bool IdleSchedulerChild::SetPaused() {
|
||||
if (mChildId && CanSend() && mActiveCounter->Memory()) {
|
||||
--(static_cast<Atomic<int32_t>*>(mActiveCounter->Memory())[mChildId]);
|
||||
if (mChildId && CanSend() && mActiveCounter.memory()) {
|
||||
--(static_cast<Atomic<int32_t>*>(mActiveCounter.memory())[mChildId]);
|
||||
// The following expression reduces the global activity count and checks if
|
||||
// it drops below the cpu counter limit.
|
||||
return (static_cast<Atomic<int32_t>*>(mActiveCounter->Memory())
|
||||
[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER])-- ==
|
||||
static_cast<Atomic<int32_t>*>(
|
||||
return (static_cast<Atomic<int32_t>*>(
|
||||
mActiveCounter
|
||||
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER];
|
||||
.memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER])-- ==
|
||||
static_cast<Atomic<int32_t>*>(
|
||||
mActiveCounter.memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER];
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ipc/PIdleSchedulerChild.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
class nsIIdlePeriod;
|
||||
|
||||
@@ -58,7 +56,7 @@ class IdleSchedulerChild final : public PIdleSchedulerChild {
|
||||
friend class BackgroundChildImpl;
|
||||
|
||||
// See IdleScheduleParent::sActiveChildCounter
|
||||
RefPtr<SharedMemory> mActiveCounter = MakeRefPtr<SharedMemory>();
|
||||
base::SharedMemory mActiveCounter;
|
||||
|
||||
IdlePeriodState* mIdlePeriodState = nullptr;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
RefPtr<SharedMemory> IdleSchedulerParent::sActiveChildCounter = nullptr;
|
||||
base::SharedMemory* IdleSchedulerParent::sActiveChildCounter = nullptr;
|
||||
std::bitset<NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT>
|
||||
IdleSchedulerParent::sInUseChildCounters;
|
||||
LinkedList<IdleSchedulerParent> IdleSchedulerParent::sIdleAndGCRequests;
|
||||
@@ -107,9 +107,9 @@ void IdleSchedulerParent::CalculateNumIdleTasks() {
|
||||
std::min(std::max(sNumCPUs / sPrefConcurrentGCsCPUDivisor, 1u),
|
||||
sPrefConcurrentGCsMax);
|
||||
|
||||
if (sActiveChildCounter && sActiveChildCounter->Memory()) {
|
||||
if (sActiveChildCounter && sActiveChildCounter->memory()) {
|
||||
static_cast<Atomic<int32_t>*>(
|
||||
sActiveChildCounter->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
|
||||
sActiveChildCounter->memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
|
||||
static_cast<int32_t>(sMaxConcurrentIdleTasksInChildProcesses);
|
||||
}
|
||||
IdleSchedulerParent::Schedule(nullptr);
|
||||
@@ -120,13 +120,13 @@ IdleSchedulerParent::~IdleSchedulerParent() {
|
||||
// that is the case.
|
||||
if (mChildId) {
|
||||
sInUseChildCounters[mChildId] = false;
|
||||
if (sActiveChildCounter && sActiveChildCounter->Memory() &&
|
||||
if (sActiveChildCounter && sActiveChildCounter->memory() &&
|
||||
static_cast<Atomic<int32_t>*>(
|
||||
sActiveChildCounter->Memory())[mChildId]) {
|
||||
sActiveChildCounter->memory())[mChildId]) {
|
||||
--static_cast<Atomic<int32_t>*>(
|
||||
sActiveChildCounter
|
||||
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER];
|
||||
static_cast<Atomic<int32_t>*>(sActiveChildCounter->Memory())[mChildId] =
|
||||
->memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER];
|
||||
static_cast<Atomic<int32_t>*>(sActiveChildCounter->memory())[mChildId] =
|
||||
0;
|
||||
}
|
||||
}
|
||||
@@ -154,6 +154,7 @@ IdleSchedulerParent::~IdleSchedulerParent() {
|
||||
sChildProcessesAlive--;
|
||||
if (sChildProcessesAlive == 0) {
|
||||
MOZ_ASSERT(sIdleAndGCRequests.isEmpty());
|
||||
delete sActiveChildCounter;
|
||||
sActiveChildCounter = nullptr;
|
||||
|
||||
if (sStarvationPreventer) {
|
||||
@@ -177,23 +178,24 @@ IPCResult IdleSchedulerParent::RecvInitForIdleUse(
|
||||
// Create a shared memory object which is shared across all the relevant
|
||||
// processes.
|
||||
if (!sActiveChildCounter) {
|
||||
sActiveChildCounter = MakeRefPtr<SharedMemory>();
|
||||
sActiveChildCounter = new base::SharedMemory();
|
||||
size_t shmemSize = NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT * sizeof(int32_t);
|
||||
if (sActiveChildCounter->Create(shmemSize) &&
|
||||
sActiveChildCounter->Map(shmemSize)) {
|
||||
memset(sActiveChildCounter->Memory(), 0, shmemSize);
|
||||
memset(sActiveChildCounter->memory(), 0, shmemSize);
|
||||
sInUseChildCounters[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER] = true;
|
||||
sInUseChildCounters[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] = true;
|
||||
static_cast<Atomic<int32_t>*>(
|
||||
sActiveChildCounter
|
||||
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
|
||||
->memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
|
||||
static_cast<int32_t>(sMaxConcurrentIdleTasksInChildProcesses);
|
||||
} else {
|
||||
delete sActiveChildCounter;
|
||||
sActiveChildCounter = nullptr;
|
||||
}
|
||||
}
|
||||
Maybe<SharedMemory::Handle> activeCounter;
|
||||
if (SharedMemory::Handle handle =
|
||||
Maybe<SharedMemoryHandle> activeCounter;
|
||||
if (SharedMemoryHandle handle =
|
||||
sActiveChildCounter ? sActiveChildCounter->CloneHandle() : nullptr) {
|
||||
activeCounter.emplace(std::move(handle));
|
||||
}
|
||||
@@ -210,7 +212,7 @@ IPCResult IdleSchedulerParent::RecvInitForIdleUse(
|
||||
// If there wasn't an empty item, we'll fallback to 0.
|
||||
mChildId = unusedId;
|
||||
|
||||
aResolve(std::tuple<mozilla::Maybe<SharedMemory::Handle>&&, const uint32_t&>(
|
||||
aResolve(std::tuple<mozilla::Maybe<SharedMemoryHandle>&&, const uint32_t&>(
|
||||
std::move(activeCounter), mChildId));
|
||||
return IPC_OK();
|
||||
}
|
||||
@@ -320,7 +322,7 @@ int32_t IdleSchedulerParent::ActiveCount() {
|
||||
if (sActiveChildCounter) {
|
||||
return (static_cast<Atomic<int32_t>*>(
|
||||
sActiveChildCounter
|
||||
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]);
|
||||
->memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ipc/PIdleSchedulerParent.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "base/shared_memory.h"
|
||||
#include <bitset>
|
||||
|
||||
#define NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT 1024
|
||||
@@ -89,7 +88,7 @@ class IdleSchedulerParent final
|
||||
// This way the global activity can be checked in a fast way by just looking
|
||||
// at [0] value.
|
||||
// [1] is used for cpu count for child processes.
|
||||
static RefPtr<SharedMemory> sActiveChildCounter;
|
||||
static base::SharedMemory* sActiveChildCounter;
|
||||
// A bit is set if there is a child with child Id as the offset.
|
||||
// The bit is used to check per child specific activity counters in
|
||||
// sActiveChildCounter.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/* -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 protocol PBackground;
|
||||
using mozilla::TimeDuration from "mozilla/TimeStamp.h";
|
||||
[MoveOnly] using mozilla::ipc::SharedMemoryHandle from "mozilla/ipc/SharedMemory.h";
|
||||
[MoveOnly] using base::SharedMemoryHandle from "base/shared_memory.h";
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
@@ -32,7 +32,8 @@ namespace ipc {
|
||||
* process, child process informs the scheduler and the process is moved back
|
||||
* to the default queue.
|
||||
*/
|
||||
async protocol PIdleScheduler {
|
||||
async protocol PIdleScheduler
|
||||
{
|
||||
manager PBackground;
|
||||
|
||||
child:
|
||||
@@ -43,8 +44,8 @@ parent:
|
||||
async RequestIdleTime(uint64_t id, TimeDuration budget);
|
||||
async IdleTimeUsed(uint64_t id);
|
||||
|
||||
// Child can send explicit Schedule message to parent if it thinks parent
|
||||
// process might be able to let some other process to use idle time.
|
||||
// Child can send explicit Schedule message to parent if it thinks parent process
|
||||
// might be able to let some other process to use idle time.
|
||||
async Schedule();
|
||||
|
||||
// Note, these two messages can be sent even before InitForIdleUse.
|
||||
@@ -60,8 +61,8 @@ parent:
|
||||
// Called for ending any kind of GC.
|
||||
async DoneGC();
|
||||
|
||||
// This message is never sent. Each PIdleScheduler actor will stay alive as
|
||||
// long as its PBackground manager.
|
||||
// This message is never sent. Each PIdleScheduler actor will stay alive as long as
|
||||
// its PBackground manager.
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
|
||||
@@ -55,9 +55,9 @@ void ProcessChild::AddPlatformBuildID(geckoargs::ChildProcessArgs& aExtraArgs) {
|
||||
|
||||
/* static */
|
||||
bool ProcessChild::InitPrefs(int aArgc, char* aArgv[]) {
|
||||
Maybe<SharedMemoryHandle> prefsHandle =
|
||||
Maybe<UniqueFileHandle> prefsHandle =
|
||||
geckoargs::sPrefsHandle.Get(aArgc, aArgv);
|
||||
Maybe<SharedMemoryHandle> prefMapHandle =
|
||||
Maybe<UniqueFileHandle> prefMapHandle =
|
||||
geckoargs::sPrefMapHandle.Get(aArgc, aArgv);
|
||||
Maybe<uint64_t> prefsLen = geckoargs::sPrefsLen.Get(aArgc, aArgv);
|
||||
Maybe<uint64_t> prefMapSize = geckoargs::sPrefMapSize.Get(aArgc, aArgv);
|
||||
|
||||
@@ -12,10 +12,9 @@
|
||||
|
||||
#include "mozilla/GeckoArgs.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "base/shared_memory.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
@@ -39,9 +38,9 @@ class SharedPreferenceSerializer final {
|
||||
size_t GetPrefMapSize() const { return mPrefMapSize; }
|
||||
size_t GetPrefsLength() const { return mPrefsLength; }
|
||||
|
||||
const SharedMemoryHandle& GetPrefsHandle() const { return mPrefsHandle; }
|
||||
const UniqueFileHandle& GetPrefsHandle() const { return mPrefsHandle; }
|
||||
|
||||
const SharedMemoryHandle& GetPrefMapHandle() const { return mPrefMapHandle; }
|
||||
const UniqueFileHandle& GetPrefMapHandle() const { return mPrefMapHandle; }
|
||||
|
||||
void AddSharedPrefCmdLineArgs(GeckoChildProcessHost& procHost,
|
||||
geckoargs::ChildProcessArgs& aExtraOpts) const;
|
||||
@@ -50,8 +49,8 @@ class SharedPreferenceSerializer final {
|
||||
DISALLOW_COPY_AND_ASSIGN(SharedPreferenceSerializer);
|
||||
size_t mPrefMapSize;
|
||||
size_t mPrefsLength;
|
||||
SharedMemoryHandle mPrefMapHandle;
|
||||
SharedMemoryHandle mPrefsHandle;
|
||||
UniqueFileHandle mPrefMapHandle;
|
||||
UniqueFileHandle mPrefsHandle;
|
||||
};
|
||||
|
||||
class SharedPreferenceDeserializer final {
|
||||
@@ -59,18 +58,18 @@ class SharedPreferenceDeserializer final {
|
||||
SharedPreferenceDeserializer();
|
||||
~SharedPreferenceDeserializer();
|
||||
|
||||
bool DeserializeFromSharedMemory(SharedMemoryHandle aPrefsHandle,
|
||||
SharedMemoryHandle aPrefMapHandle,
|
||||
bool DeserializeFromSharedMemory(UniqueFileHandle aPrefsHandle,
|
||||
UniqueFileHandle aPrefMapHandle,
|
||||
uint64_t aPrefsLen, uint64_t aPrefMapSize);
|
||||
|
||||
const SharedMemoryHandle& GetPrefMapHandle() const;
|
||||
const FileDescriptor& GetPrefMapHandle() const;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(SharedPreferenceDeserializer);
|
||||
Maybe<SharedMemoryHandle> mPrefMapHandle;
|
||||
Maybe<FileDescriptor> mPrefMapHandle;
|
||||
Maybe<size_t> mPrefsLen;
|
||||
Maybe<size_t> mPrefMapSize;
|
||||
RefPtr<SharedMemory> mShmem = MakeRefPtr<SharedMemory>();
|
||||
base::SharedMemory mShmem;
|
||||
};
|
||||
|
||||
// Generate command line argument to spawn a child process. If the shared memory
|
||||
@@ -80,7 +79,7 @@ void ExportSharedJSInit(GeckoChildProcessHost& procHost,
|
||||
|
||||
// Initialize the content used by the JS engine during the initialization of a
|
||||
// JS::Runtime.
|
||||
bool ImportSharedJSInit(SharedMemoryHandle aJsInitHandle, uint64_t aJsInitLen);
|
||||
bool ImportSharedJSInit(UniqueFileHandle aJsInitHandle, uint64_t aJsInitLen);
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/GeckoArgs.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/RemoteType.h"
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
@@ -40,7 +39,8 @@ SharedPreferenceSerializer::SharedPreferenceSerializer(
|
||||
bool SharedPreferenceSerializer::SerializeToSharedMemory(
|
||||
const GeckoProcessType aDestinationProcessType,
|
||||
const nsACString& aDestinationRemoteType) {
|
||||
mPrefMapHandle = Preferences::EnsureSnapshot(&mPrefMapSize);
|
||||
mPrefMapHandle =
|
||||
Preferences::EnsureSnapshot(&mPrefMapSize).TakePlatformHandle();
|
||||
|
||||
bool destIsWebContent =
|
||||
aDestinationProcessType == GeckoProcessType_Content &&
|
||||
@@ -52,31 +52,30 @@ bool SharedPreferenceSerializer::SerializeToSharedMemory(
|
||||
Preferences::SerializePreferences(prefs, destIsWebContent);
|
||||
mPrefsLength = prefs.Length();
|
||||
|
||||
RefPtr<SharedMemory> shm = MakeRefPtr<SharedMemory>();
|
||||
base::SharedMemory shm;
|
||||
// Set up the shared memory.
|
||||
if (!shm->Create(prefs.Length())) {
|
||||
if (!shm.Create(prefs.Length())) {
|
||||
NS_ERROR("failed to create shared memory in the parent");
|
||||
return false;
|
||||
}
|
||||
if (!shm->Map(prefs.Length())) {
|
||||
if (!shm.Map(prefs.Length())) {
|
||||
NS_ERROR("failed to map shared memory in the parent");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy the serialized prefs into the shared memory.
|
||||
memcpy(static_cast<char*>(shm->Memory()), prefs.get(), mPrefsLength);
|
||||
memcpy(static_cast<char*>(shm.memory()), prefs.get(), mPrefsLength);
|
||||
|
||||
mPrefsHandle = shm->TakeHandleAndUnmap();
|
||||
mPrefsHandle = shm.TakeHandle();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SharedPreferenceSerializer::AddSharedPrefCmdLineArgs(
|
||||
mozilla::ipc::GeckoChildProcessHost& procHost,
|
||||
geckoargs::ChildProcessArgs& aExtraOpts) const {
|
||||
SharedMemoryHandle prefsHandle = SharedMemory::CloneHandle(GetPrefsHandle());
|
||||
UniqueFileHandle prefsHandle = DuplicateFileHandle(GetPrefsHandle());
|
||||
MOZ_RELEASE_ASSERT(prefsHandle, "failed to duplicate prefs handle");
|
||||
SharedMemoryHandle prefMapHandle =
|
||||
SharedMemory::CloneHandle(GetPrefMapHandle());
|
||||
UniqueFileHandle prefMapHandle = DuplicateFileHandle(GetPrefMapHandle());
|
||||
MOZ_RELEASE_ASSERT(prefMapHandle, "failed to duplicate pref map handle");
|
||||
|
||||
// Pass the handles and lengths via command line flags.
|
||||
@@ -95,7 +94,7 @@ SharedPreferenceDeserializer::~SharedPreferenceDeserializer() {
|
||||
}
|
||||
|
||||
bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
|
||||
SharedMemoryHandle aPrefsHandle, SharedMemoryHandle aPrefMapHandle,
|
||||
UniqueFileHandle aPrefsHandle, UniqueFileHandle aPrefMapHandle,
|
||||
uint64_t aPrefsLen, uint64_t aPrefMapSize) {
|
||||
if (!aPrefsHandle || !aPrefMapHandle || !aPrefsLen || !aPrefMapSize) {
|
||||
return false;
|
||||
@@ -112,23 +111,21 @@ bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
|
||||
Preferences::InitSnapshot(mPrefMapHandle.ref(), *mPrefMapSize);
|
||||
|
||||
// Set up early prefs from the shared memory.
|
||||
if (!mShmem->SetHandle(std::move(aPrefsHandle),
|
||||
SharedMemory::RightsReadOnly)) {
|
||||
if (!mShmem.SetHandle(std::move(aPrefsHandle), /* read_only */ true)) {
|
||||
NS_ERROR("failed to open shared memory in the child");
|
||||
return false;
|
||||
}
|
||||
if (!mShmem->Map(*mPrefsLen)) {
|
||||
if (!mShmem.Map(*mPrefsLen)) {
|
||||
NS_ERROR("failed to map shared memory in the child");
|
||||
return false;
|
||||
}
|
||||
Preferences::DeserializePreferences(static_cast<char*>(mShmem->Memory()),
|
||||
Preferences::DeserializePreferences(static_cast<char*>(mShmem.memory()),
|
||||
*mPrefsLen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const SharedMemoryHandle& SharedPreferenceDeserializer::GetPrefMapHandle()
|
||||
const {
|
||||
const FileDescriptor& SharedPreferenceDeserializer::GetPrefMapHandle() const {
|
||||
MOZ_ASSERT(mPrefMapHandle.isSome());
|
||||
|
||||
return mPrefMapHandle.ref();
|
||||
@@ -141,12 +138,12 @@ void ExportSharedJSInit(mozilla::ipc::GeckoChildProcessHost& procHost,
|
||||
return;
|
||||
#else
|
||||
auto& shmem = xpc::SelfHostedShmem::GetSingleton();
|
||||
SharedMemoryHandle handle = SharedMemory::CloneHandle(shmem.Handle());
|
||||
UniqueFileHandle handle = DuplicateFileHandle(shmem.Handle());
|
||||
size_t len = shmem.Content().Length();
|
||||
|
||||
// If the file is not found or the content is empty, then we would start the
|
||||
// content process without this optimization.
|
||||
if (!SharedMemory::IsHandleValid(handle) || !len) {
|
||||
if (!handle || !len) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,7 +153,7 @@ void ExportSharedJSInit(mozilla::ipc::GeckoChildProcessHost& procHost,
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ImportSharedJSInit(SharedMemoryHandle aJsInitHandle, uint64_t aJsInitLen) {
|
||||
bool ImportSharedJSInit(UniqueFileHandle aJsInitHandle, uint64_t aJsInitLen) {
|
||||
// This is an optimization, and as such we can safely recover if the command
|
||||
// line argument are not provided.
|
||||
if (!aJsInitLen || !aJsInitHandle) {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#ifndef MOZILLA_IPC_RAWSHMEM_H_
|
||||
#define MOZILLA_IPC_RAWSHMEM_H_
|
||||
|
||||
#include "chrome/common/ipc_message_utils.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "mozilla/Span.h"
|
||||
#include <utility>
|
||||
|
||||
@@ -4,14 +4,8 @@
|
||||
* 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/. */
|
||||
|
||||
/* This source code was derived from Chromium code, and as such is also subject
|
||||
* to the [Chromium license](ipc/chromium/src/LICENSE). */
|
||||
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "chrome/common/ipc_message_utils.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
|
||||
@@ -59,7 +53,6 @@ SharedMemory::SharedMemory() : mAllocSize(0), mMappedSize(0) {
|
||||
SharedMemory::~SharedMemory() {
|
||||
Unmap();
|
||||
CloseHandle();
|
||||
ResetImpl();
|
||||
|
||||
MOZ_ASSERT(gShmemAllocated >= mAllocSize,
|
||||
"Can't destroy more than allocated");
|
||||
@@ -67,108 +60,8 @@ SharedMemory::~SharedMemory() {
|
||||
mAllocSize = 0;
|
||||
}
|
||||
|
||||
bool SharedMemory::Create(size_t aNBytes, bool freezable) {
|
||||
MOZ_ASSERT(!IsValid(), "already initialized");
|
||||
bool ok = CreateImpl(aNBytes, freezable);
|
||||
if (ok) {
|
||||
mAllocSize = aNBytes;
|
||||
mFreezable = freezable;
|
||||
mReadOnly = false;
|
||||
mExternalHandle = false;
|
||||
gShmemAllocated += mAllocSize;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool SharedMemory::Map(size_t aNBytes, void* fixedAddress) {
|
||||
if (!mHandle) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(!mMemory, "can't map memory when a mapping already exists");
|
||||
auto address = MapImpl(aNBytes, fixedAddress);
|
||||
if (address) {
|
||||
mMappedSize = aNBytes;
|
||||
mMemory = UniqueMapping(*address, MappingDeleter(mMappedSize));
|
||||
gShmemMapped += mMappedSize;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SharedMemory::Unmap() {
|
||||
if (!mMemory) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(gShmemMapped >= mMappedSize, "Can't unmap more than mapped");
|
||||
mMemory = nullptr;
|
||||
gShmemMapped -= std::exchange(mMappedSize, 0);
|
||||
}
|
||||
|
||||
void* SharedMemory::Memory() const {
|
||||
#ifdef FUZZING
|
||||
return SharedMemoryFuzzer::MutateSharedMemory(mMemory.get(), mAllocSize);
|
||||
#else
|
||||
return mMemory.get();
|
||||
#endif
|
||||
}
|
||||
|
||||
Span<uint8_t> SharedMemory::TakeMapping() {
|
||||
// NOTE: this doesn't reduce gShmemMapped since it _is_ still mapped memory
|
||||
// (and will be until the process terminates).
|
||||
return {static_cast<uint8_t*>(mMemory.release()),
|
||||
std::exchange(mMappedSize, 0)};
|
||||
}
|
||||
|
||||
SharedMemory::Handle SharedMemory::TakeHandle() {
|
||||
gShmemAllocated -= mAllocSize;
|
||||
mAllocSize = 0;
|
||||
return std::move(mHandle);
|
||||
}
|
||||
|
||||
bool SharedMemory::SetHandle(Handle aHandle, OpenRights aRights) {
|
||||
MOZ_ASSERT(!IsValid(),
|
||||
"SetHandle cannot be called when a valid handle is already held");
|
||||
ResetImpl();
|
||||
mHandle = std::move(aHandle);
|
||||
mAllocSize = 0;
|
||||
mMappedSize = 0;
|
||||
mFreezable = false;
|
||||
mReadOnly = aRights == OpenRights::RightsReadOnly;
|
||||
mExternalHandle = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
|
||||
MOZ_ASSERT(mHandle);
|
||||
MOZ_ASSERT(!mReadOnly);
|
||||
MOZ_ASSERT(mFreezable);
|
||||
if (ro_out == this) {
|
||||
MOZ_ASSERT(
|
||||
!mMemory,
|
||||
"Memory cannot be mapped when creating a read-only copy of this.");
|
||||
}
|
||||
auto handle = ReadOnlyCopyImpl();
|
||||
auto allocSize = mAllocSize;
|
||||
TakeHandle();
|
||||
if (!handle) {
|
||||
return false;
|
||||
}
|
||||
mFreezable = false;
|
||||
|
||||
// Reset ro_out (unmapping, etc).
|
||||
ro_out->~SharedMemory();
|
||||
|
||||
ro_out->mHandle = std::move(*handle);
|
||||
ro_out->mAllocSize = allocSize;
|
||||
gShmemAllocated += ro_out->mAllocSize;
|
||||
ro_out->mReadOnly = true;
|
||||
ro_out->mFreezable = false;
|
||||
ro_out->mExternalHandle = mExternalHandle;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::WriteHandle(IPC::MessageWriter* aWriter) {
|
||||
Handle handle = CloneHandle(mHandle);
|
||||
Handle handle = CloneHandle();
|
||||
if (!handle) {
|
||||
return false;
|
||||
}
|
||||
@@ -183,9 +76,6 @@ bool SharedMemory::ReadHandle(IPC::MessageReader* aReader) {
|
||||
}
|
||||
|
||||
void SharedMemory::Protect(char* aAddr, size_t aSize, int aRights) {
|
||||
// Don't allow altering of rights on freezable shared memory handles.
|
||||
MOZ_ASSERT(!mFreezable);
|
||||
|
||||
char* memStart = reinterpret_cast<char*>(Memory());
|
||||
if (!memStart) MOZ_CRASH("SharedMemory region points at NULL!");
|
||||
char* memEnd = memStart + Size();
|
||||
@@ -208,4 +98,37 @@ size_t SharedMemory::PageAlignedSize(size_t aSize) {
|
||||
return pageSize * nPagesNeeded;
|
||||
}
|
||||
|
||||
bool SharedMemory::Create(size_t aNBytes) {
|
||||
bool ok = CreateImpl(aNBytes);
|
||||
if (ok) {
|
||||
mAllocSize = aNBytes;
|
||||
gShmemAllocated += mAllocSize;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool SharedMemory::Map(size_t aNBytes, void* fixedAddress) {
|
||||
bool ok = MapImpl(aNBytes, fixedAddress);
|
||||
if (ok) {
|
||||
mMappedSize = aNBytes;
|
||||
gShmemMapped += mMappedSize;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void SharedMemory::Unmap() {
|
||||
MOZ_ASSERT(gShmemMapped >= mMappedSize, "Can't unmap more than mapped");
|
||||
UnmapImpl(mMappedSize);
|
||||
gShmemMapped -= mMappedSize;
|
||||
mMappedSize = 0;
|
||||
}
|
||||
|
||||
void* SharedMemory::Memory() const {
|
||||
#ifdef FUZZING
|
||||
return SharedMemoryFuzzer::MutateSharedMemory(MemoryImpl(), mAllocSize);
|
||||
#else
|
||||
return MemoryImpl();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace mozilla::ipc
|
||||
|
||||
@@ -4,56 +4,27 @@
|
||||
* 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/. */
|
||||
|
||||
/* This source code was derived from Chromium code, and as such is also subject
|
||||
* to the [Chromium license](ipc/chromium/src/LICENSE). */
|
||||
|
||||
#ifndef mozilla_ipc_SharedMemory_h
|
||||
#define mozilla_ipc_SharedMemory_h
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "chrome/common/ipc_message_utils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "nsISupportsImpl.h" // NS_INLINE_DECL_REFCOUNTING
|
||||
|
||||
#if !(defined(XP_DARWIN) || defined(XP_WIN))
|
||||
# include <string>
|
||||
#ifdef XP_DARWIN
|
||||
# include "mozilla/ipc/SharedMemoryImpl_mach.h"
|
||||
#else
|
||||
# include "mozilla/ipc/SharedMemoryImpl_chromium.h"
|
||||
#endif
|
||||
|
||||
namespace IPC {
|
||||
class MessageWriter;
|
||||
class MessageReader;
|
||||
} // namespace IPC
|
||||
|
||||
namespace {
|
||||
enum Rights { RightsNone = 0, RightsRead = 1 << 0, RightsWrite = 1 << 1 };
|
||||
} // namespace
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
// Rust Bindgen code doesn't actually use these types, but `UniqueFileHandle`
|
||||
// and `UniqueMachSendRight` aren't defined and some headers need to type check,
|
||||
// so we define a dummy type.
|
||||
#if defined(RUST_BINDGEN)
|
||||
using SharedMemoryHandle = void*;
|
||||
#elif defined(XP_DARWIN)
|
||||
using SharedMemoryHandle = mozilla::UniqueMachSendRight;
|
||||
#else
|
||||
using SharedMemoryHandle = mozilla::UniqueFileHandle;
|
||||
#endif
|
||||
|
||||
class SharedMemory {
|
||||
class SharedMemory : public SharedMemoryImpl {
|
||||
~SharedMemory();
|
||||
|
||||
/// # Provided methods
|
||||
public:
|
||||
using Handle = SharedMemoryHandle;
|
||||
|
||||
enum OpenRights {
|
||||
RightsReadOnly = RightsRead,
|
||||
RightsReadWrite = RightsRead | RightsWrite,
|
||||
};
|
||||
|
||||
SharedMemory();
|
||||
|
||||
// bug 1168843, compositor thread may create shared memory instances that are
|
||||
@@ -62,123 +33,32 @@ class SharedMemory {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedMemory)
|
||||
|
||||
size_t Size() const { return mMappedSize; }
|
||||
size_t MaxSize() const { return mAllocSize; }
|
||||
|
||||
bool Create(size_t nBytes, bool freezable = false);
|
||||
bool Map(size_t nBytes, void* fixedAddress = nullptr);
|
||||
void Unmap();
|
||||
void* Memory() const;
|
||||
/// Take the mapping memory.
|
||||
///
|
||||
/// This prevents unmapping the memory.
|
||||
Span<uint8_t> TakeMapping();
|
||||
|
||||
Handle TakeHandleAndUnmap() {
|
||||
auto handle = TakeHandle();
|
||||
Unmap();
|
||||
return handle;
|
||||
}
|
||||
Handle TakeHandle();
|
||||
Handle CloneHandle() {
|
||||
mFreezable = false;
|
||||
return SharedMemory::CloneHandle(mHandle);
|
||||
}
|
||||
void CloseHandle() { TakeHandle(); }
|
||||
bool SetHandle(Handle aHandle, OpenRights aRights);
|
||||
bool IsValid() const { return IsHandleValid(mHandle); }
|
||||
static bool IsHandleValid(const Handle& aHandle) {
|
||||
// `operator!=` had ambiguous overload resolution with the windows Handle
|
||||
// (mozilla::UniqueFileHandle), so invert `operator==` instead.
|
||||
return !(aHandle == NULLHandle());
|
||||
}
|
||||
static Handle NULLHandle() { return nullptr; }
|
||||
|
||||
bool CreateFreezable(size_t nBytes) { return Create(nBytes, true); }
|
||||
|
||||
[[nodiscard]] bool Freeze() {
|
||||
Unmap();
|
||||
return ReadOnlyCopy(this);
|
||||
}
|
||||
|
||||
bool WriteHandle(IPC::MessageWriter* aWriter);
|
||||
bool ReadHandle(IPC::MessageReader* aReader);
|
||||
void Protect(char* aAddr, size_t aSize, int aRights);
|
||||
|
||||
static size_t PageAlignedSize(size_t aSize);
|
||||
|
||||
/// Public methods which should be defined as part of each implementation.
|
||||
public:
|
||||
[[nodiscard]] bool ReadOnlyCopy(SharedMemory* ro_out);
|
||||
|
||||
static void SystemProtect(char* aAddr, size_t aSize, int aRights);
|
||||
[[nodiscard]] static bool SystemProtectFallible(char* aAddr, size_t aSize,
|
||||
int aRights);
|
||||
static Handle CloneHandle(const Handle& aHandle);
|
||||
static size_t SystemPageSize();
|
||||
static void* FindFreeAddressSpace(size_t size);
|
||||
static size_t PageAlignedSize(size_t aSize);
|
||||
|
||||
bool Create(size_t nBytes);
|
||||
bool Map(size_t nBytes, void* fixedAddress = nullptr);
|
||||
void Unmap();
|
||||
void* Memory() const;
|
||||
|
||||
/// Private methods which should be defined as part of each implementation.
|
||||
private:
|
||||
bool CreateImpl(size_t size, bool freezable);
|
||||
Maybe<void*> MapImpl(size_t nBytes, void* fixedAddress);
|
||||
static void UnmapImpl(size_t nBytes, void* address);
|
||||
Maybe<Handle> ReadOnlyCopyImpl();
|
||||
void ResetImpl();
|
||||
|
||||
/// Common members
|
||||
private:
|
||||
struct MappingDeleter {
|
||||
size_t mMappedSize = 0;
|
||||
explicit MappingDeleter(size_t size) : mMappedSize(size) {}
|
||||
MappingDeleter() = default;
|
||||
void operator()(void* ptr) {
|
||||
MOZ_ASSERT(mMappedSize != 0);
|
||||
UnmapImpl(mMappedSize, ptr);
|
||||
// Guard against multiple calls of the same deleter, which shouldn't
|
||||
// happen (but could, if `UniquePtr::reset` were used). Calling
|
||||
// `munmap` with an incorrect non-zero length would be bad.
|
||||
mMappedSize = 0;
|
||||
}
|
||||
};
|
||||
using UniqueMapping = mozilla::UniquePtr<void, MappingDeleter>;
|
||||
|
||||
// The held handle, if any.
|
||||
Handle mHandle = NULLHandle();
|
||||
// The size of the shmem region requested in Create(), if
|
||||
// successful. SharedMemory instances that are opened from a
|
||||
// foreign handle have an alloc size of 0, even though they have
|
||||
// access to the alloc-size information.
|
||||
size_t mAllocSize;
|
||||
// The memory mapping, if any.
|
||||
UniqueMapping mMemory;
|
||||
// The size of the region mapped in Map(), if successful. All
|
||||
// SharedMemorys that are mapped have a non-zero mapped size.
|
||||
size_t mMappedSize;
|
||||
// Whether the handle held is freezable.
|
||||
bool mFreezable = false;
|
||||
// Whether the handle held is read-only.
|
||||
bool mReadOnly = false;
|
||||
// Whether the handle held is external (set with `SetHandle`).
|
||||
bool mExternalHandle = false;
|
||||
|
||||
#if !defined(XP_DARWIN) && !defined(XP_WIN)
|
||||
/// # Unix/POSIX-specific methods and members.
|
||||
public:
|
||||
// If named POSIX shm is being used, append the prefix (including
|
||||
// the leading '/') that would be used by a process with the given
|
||||
// pid to the given string and return true. If not, return false.
|
||||
// (This is public so that the Linux sandboxing code can use it.)
|
||||
static bool AppendPosixShmPrefix(std::string* str, pid_t pid);
|
||||
|
||||
// Similar, but simply returns whether POSIX shm is in use.
|
||||
static bool UsingPosixShm();
|
||||
|
||||
# if !defined(ANDROID) && !defined(RUST_BINDGEN)
|
||||
private:
|
||||
mozilla::UniqueFileHandle mFrozenFile;
|
||||
bool mIsMemfd = false;
|
||||
# endif
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla::ipc
|
||||
|
||||
47
ipc/glue/SharedMemoryImpl_chromium.cpp
Normal file
47
ipc/glue/SharedMemoryImpl_chromium.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/* -*- 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 "mozilla/ipc/SharedMemoryImpl_chromium.h"
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
SharedMemoryImpl::Handle SharedMemoryImpl::CloneHandle() {
|
||||
return mSharedMemory.CloneHandle();
|
||||
}
|
||||
|
||||
SharedMemoryImpl::Handle SharedMemoryImpl::TakeHandle() {
|
||||
return mSharedMemory.TakeHandle(false);
|
||||
}
|
||||
|
||||
bool SharedMemoryImpl::IsHandleValid(const Handle& aHandle) const {
|
||||
return base::SharedMemory::IsHandleValid(aHandle);
|
||||
}
|
||||
|
||||
bool SharedMemoryImpl::SetHandle(Handle aHandle, OpenRights aRights) {
|
||||
return mSharedMemory.SetHandle(std::move(aHandle), aRights == RightsReadOnly);
|
||||
}
|
||||
|
||||
SharedMemoryImpl::Handle SharedMemoryImpl::NULLHandle() {
|
||||
return base::SharedMemory::NULLHandle();
|
||||
}
|
||||
|
||||
void* SharedMemoryImpl::FindFreeAddressSpace(size_t size) {
|
||||
return base::SharedMemory::FindFreeAddressSpace(size);
|
||||
}
|
||||
|
||||
bool SharedMemoryImpl::CreateImpl(size_t size) {
|
||||
return mSharedMemory.Create(size);
|
||||
}
|
||||
|
||||
bool SharedMemoryImpl::MapImpl(size_t nBytes, void* fixedAddress) {
|
||||
return mSharedMemory.Map(nBytes, fixedAddress);
|
||||
}
|
||||
|
||||
void SharedMemoryImpl::UnmapImpl(size_t mappedSize) { mSharedMemory.Unmap(); }
|
||||
|
||||
void* SharedMemoryImpl::MemoryImpl() const { return mSharedMemory.memory(); }
|
||||
|
||||
} // namespace mozilla::ipc
|
||||
51
ipc/glue/SharedMemoryImpl_chromium.h
Normal file
51
ipc/glue/SharedMemoryImpl_chromium.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_SharedMemoryImpl_posix_h
|
||||
#define mozilla_ipc_SharedMemoryImpl_posix_h
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
|
||||
namespace {
|
||||
enum Rights { RightsNone = 0, RightsRead = 1 << 0, RightsWrite = 1 << 1 };
|
||||
} // namespace
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
class SharedMemoryImpl {
|
||||
public:
|
||||
using Handle = base::SharedMemoryHandle;
|
||||
|
||||
enum OpenRights {
|
||||
RightsReadOnly = RightsRead,
|
||||
RightsReadWrite = RightsRead | RightsWrite,
|
||||
};
|
||||
|
||||
Handle CloneHandle();
|
||||
Handle TakeHandle();
|
||||
|
||||
bool IsHandleValid(const Handle& aHandle) const;
|
||||
bool SetHandle(Handle aHandle, OpenRights aRights);
|
||||
|
||||
static Handle NULLHandle();
|
||||
static void* FindFreeAddressSpace(size_t size);
|
||||
|
||||
protected:
|
||||
SharedMemoryImpl() = default;
|
||||
~SharedMemoryImpl() {}
|
||||
|
||||
bool CreateImpl(size_t size);
|
||||
bool MapImpl(size_t nBytes, void* fixedAddress);
|
||||
void UnmapImpl(size_t mappedSize);
|
||||
void* MemoryImpl() const;
|
||||
|
||||
private:
|
||||
base::SharedMemory mSharedMemory;
|
||||
};
|
||||
|
||||
} // namespace mozilla::ipc
|
||||
|
||||
#endif
|
||||
170
ipc/glue/SharedMemoryImpl_mach.cpp
Normal file
170
ipc/glue/SharedMemoryImpl_mach.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/* -*- 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 "mozilla/ipc/SharedMemoryImpl_mach.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <mach/vm_map.h>
|
||||
#include <mach/mach_port.h>
|
||||
#if defined(XP_IOS)
|
||||
# include <mach/vm_map.h>
|
||||
# define mach_vm_address_t vm_address_t
|
||||
# define mach_vm_map vm_map
|
||||
# define mach_vm_read vm_read
|
||||
# define mach_vm_region_recurse vm_region_recurse_64
|
||||
# define mach_vm_size_t vm_size_t
|
||||
#else
|
||||
# include <mach/mach_vm.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/Printf.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
# define LOG_ERROR(str, args...) \
|
||||
PR_BEGIN_MACRO \
|
||||
mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ##args); \
|
||||
NS_WARNING(msg.get()); \
|
||||
PR_END_MACRO
|
||||
#else
|
||||
# define LOG_ERROR(str, args...) \
|
||||
do { /* nothing */ \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
SharedMemoryImpl::SharedMemoryImpl()
|
||||
: mPort(MACH_PORT_NULL), mMemory(nullptr), mOpenRights(RightsReadWrite) {}
|
||||
|
||||
bool SharedMemoryImpl::SetHandle(Handle aHandle, OpenRights aRights) {
|
||||
MOZ_ASSERT(mPort == MACH_PORT_NULL, "already initialized");
|
||||
|
||||
mPort = std::move(aHandle);
|
||||
mOpenRights = aRights;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void* toPointer(mach_vm_address_t address) {
|
||||
return reinterpret_cast<void*>(static_cast<uintptr_t>(address));
|
||||
}
|
||||
|
||||
static inline mach_vm_address_t toVMAddress(void* pointer) {
|
||||
return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer));
|
||||
}
|
||||
|
||||
bool SharedMemoryImpl::CreateImpl(size_t size) {
|
||||
MOZ_ASSERT(mPort == MACH_PORT_NULL, "already initialized");
|
||||
|
||||
memory_object_size_t memoryObjectSize = round_page(size);
|
||||
|
||||
kern_return_t kr =
|
||||
mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
|
||||
MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
|
||||
getter_Transfers(mPort), MACH_PORT_NULL);
|
||||
if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) {
|
||||
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size,
|
||||
mach_error_string(kr), kr);
|
||||
TakeHandle();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemoryImpl::MapImpl(size_t size, void* fixedAddress) {
|
||||
MOZ_ASSERT(mMemory == nullptr);
|
||||
|
||||
if (MACH_PORT_NULL == mPort) {
|
||||
return false;
|
||||
}
|
||||
|
||||
kern_return_t kr;
|
||||
mach_vm_address_t address = toVMAddress(fixedAddress);
|
||||
|
||||
vm_prot_t vmProtection = VM_PROT_READ;
|
||||
if (mOpenRights == RightsReadWrite) {
|
||||
vmProtection |= VM_PROT_WRITE;
|
||||
}
|
||||
|
||||
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0,
|
||||
fixedAddress ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE,
|
||||
mPort.get(), 0, false, vmProtection, vmProtection,
|
||||
VM_INHERIT_NONE);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
if (!fixedAddress) {
|
||||
LOG_ERROR(
|
||||
"Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
|
||||
size, mach_task_self(), mach_port_t(mPort.get()),
|
||||
mach_error_string(kr), kr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fixedAddress && fixedAddress != toPointer(address)) {
|
||||
kr = vm_deallocate(mach_task_self(), address, size);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
LOG_ERROR(
|
||||
"Failed to unmap shared memory at unsuitable address "
|
||||
"(%zu bytes) from %x, port %x. %s (%x)\n",
|
||||
size, mach_task_self(), mach_port_t(mPort.get()),
|
||||
mach_error_string(kr), kr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
mMemory = toPointer(address);
|
||||
return true;
|
||||
}
|
||||
|
||||
void* SharedMemoryImpl::FindFreeAddressSpace(size_t size) {
|
||||
mach_vm_address_t address = 0;
|
||||
size = round_page(size);
|
||||
if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE,
|
||||
MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE, VM_PROT_NONE,
|
||||
VM_INHERIT_NONE) != KERN_SUCCESS ||
|
||||
vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
|
||||
return nullptr;
|
||||
}
|
||||
return toPointer(address);
|
||||
}
|
||||
|
||||
auto SharedMemoryImpl::CloneHandle() -> Handle {
|
||||
return mozilla::RetainMachSendRight(mPort.get());
|
||||
}
|
||||
|
||||
auto SharedMemoryImpl::TakeHandle() -> Handle {
|
||||
mOpenRights = RightsReadWrite;
|
||||
return std::move(mPort);
|
||||
}
|
||||
|
||||
void SharedMemoryImpl::UnmapImpl(size_t mappedSize) {
|
||||
if (!mMemory) {
|
||||
return;
|
||||
}
|
||||
vm_address_t address = toVMAddress(mMemory);
|
||||
kern_return_t kr =
|
||||
vm_deallocate(mach_task_self(), address, round_page(mappedSize));
|
||||
if (kr != KERN_SUCCESS) {
|
||||
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
|
||||
mach_error_string(kr), kr);
|
||||
return;
|
||||
}
|
||||
mMemory = nullptr;
|
||||
}
|
||||
|
||||
void* SharedMemoryImpl::MemoryImpl() const { return mMemory; }
|
||||
|
||||
bool SharedMemoryImpl::IsHandleValid(const Handle& aHandle) const {
|
||||
return aHandle != nullptr;
|
||||
}
|
||||
|
||||
auto SharedMemoryImpl::NULLHandle() -> Handle { return Handle(); }
|
||||
|
||||
} // namespace mozilla::ipc
|
||||
56
ipc/glue/SharedMemoryImpl_mach.h
Normal file
56
ipc/glue/SharedMemoryImpl_mach.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_SharedMemoryImpl_mach_h
|
||||
#define mozilla_ipc_SharedMemoryImpl_mach_h
|
||||
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include <mach/port.h>
|
||||
|
||||
namespace {
|
||||
enum Rights { RightsNone = 0, RightsRead = 1 << 0, RightsWrite = 1 << 1 };
|
||||
} // namespace
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
class SharedMemoryImpl {
|
||||
public:
|
||||
using Handle = mozilla::UniqueMachSendRight;
|
||||
|
||||
enum OpenRights {
|
||||
RightsReadOnly = RightsRead,
|
||||
RightsReadWrite = RightsRead | RightsWrite,
|
||||
};
|
||||
|
||||
Handle CloneHandle();
|
||||
Handle TakeHandle();
|
||||
|
||||
bool IsHandleValid(const Handle& aHandle) const;
|
||||
bool SetHandle(Handle aHandle, OpenRights aRights);
|
||||
|
||||
static Handle NULLHandle();
|
||||
static void* FindFreeAddressSpace(size_t size);
|
||||
|
||||
protected:
|
||||
SharedMemoryImpl();
|
||||
~SharedMemoryImpl() {}
|
||||
|
||||
bool CreateImpl(size_t size);
|
||||
bool MapImpl(size_t nBytes, void* fixedAddress);
|
||||
void UnmapImpl(size_t mappedSize);
|
||||
void* MemoryImpl() const;
|
||||
|
||||
private:
|
||||
mozilla::UniqueMachSendRight mPort;
|
||||
// Pointer to mapped region, null if unmapped.
|
||||
void* mMemory;
|
||||
// Access rights to map an existing region with.
|
||||
OpenRights mOpenRights;
|
||||
};
|
||||
|
||||
} // namespace mozilla::ipc
|
||||
|
||||
#endif
|
||||
@@ -1,137 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
/* This source code was derived from Chromium code, and as such is also subject
|
||||
* to the [Chromium license](ipc/chromium/src/LICENSE). */
|
||||
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mozilla/Ashmem.h"
|
||||
|
||||
#ifdef MOZ_VALGRIND
|
||||
# include <valgrind/valgrind.h>
|
||||
#endif
|
||||
|
||||
#include "base/eintr_wrapper.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/string_util.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/ProfilerThreadSleep.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "prenv.h"
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
void SharedMemory::ResetImpl() {};
|
||||
|
||||
SharedMemory::Handle SharedMemory::CloneHandle(const Handle& aHandle) {
|
||||
const int new_fd = dup(aHandle.get());
|
||||
if (new_fd < 0) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to duplicate file descriptor: "
|
||||
<< strerror(errno);
|
||||
return nullptr;
|
||||
}
|
||||
return mozilla::UniqueFileHandle(new_fd);
|
||||
}
|
||||
|
||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
||||
void* memory = mmap(nullptr, size, PROT_NONE,
|
||||
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
|
||||
if (memory == MAP_FAILED) {
|
||||
return nullptr;
|
||||
}
|
||||
munmap(memory, size);
|
||||
return memory;
|
||||
}
|
||||
|
||||
Maybe<void*> SharedMemory::MapImpl(size_t nBytes, void* fixedAddress) {
|
||||
// Don't use MAP_FIXED when a fixed_address was specified, since that can
|
||||
// replace pages that are alread mapped at that address.
|
||||
void* mem =
|
||||
mmap(fixedAddress, nBytes, PROT_READ | (mReadOnly ? 0 : PROT_WRITE),
|
||||
MAP_SHARED, mHandle.get(), 0);
|
||||
|
||||
if (mem == MAP_FAILED) {
|
||||
CHROMIUM_LOG(WARNING) << "Call to mmap failed: " << strerror(errno);
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
if (fixedAddress && mem != fixedAddress) {
|
||||
bool munmap_succeeded = munmap(mem, nBytes) == 0;
|
||||
DCHECK(munmap_succeeded) << "Call to munmap failed, errno=" << errno;
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(mem);
|
||||
}
|
||||
|
||||
void SharedMemory::UnmapImpl(size_t nBytes, void* address) {
|
||||
munmap(address, nBytes);
|
||||
}
|
||||
|
||||
// Android has its own shared memory API, ashmem. It doesn't support POSIX
|
||||
// shm_open, and the memfd support (see posix impl) also doesn't work because
|
||||
// its SELinux policy prevents the procfs operations we'd use (see bug 1670277
|
||||
// for more details).
|
||||
|
||||
bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SharedMemory::UsingPosixShm() { return false; }
|
||||
|
||||
bool SharedMemory::CreateImpl(size_t size, bool freezable) {
|
||||
DCHECK(size > 0);
|
||||
DCHECK(!mHandle);
|
||||
|
||||
int fd = mozilla::android::ashmem_create(nullptr, size);
|
||||
if (fd < 0) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
mHandle.reset(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
Maybe<SharedMemory::Handle> SharedMemory::ReadOnlyCopyImpl() {
|
||||
if (mozilla::android::ashmem_setProt(mHandle.get(), PROT_READ) != 0) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to set ashmem read-only: "
|
||||
<< strerror(errno);
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
mozilla::UniqueFileHandle ro_file = std::move(mHandle);
|
||||
|
||||
return Some(std::move(ro_file));
|
||||
}
|
||||
|
||||
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
||||
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
||||
MOZ_CRASH("can't mprotect()");
|
||||
}
|
||||
}
|
||||
|
||||
bool SharedMemory::SystemProtectFallible(char* aAddr, size_t aSize,
|
||||
int aRights) {
|
||||
int flags = 0;
|
||||
if (aRights & RightsRead) flags |= PROT_READ;
|
||||
if (aRights & RightsWrite) flags |= PROT_WRITE;
|
||||
if (RightsNone == aRights) flags = PROT_NONE;
|
||||
|
||||
return 0 == mprotect(aAddr, aSize, flags);
|
||||
}
|
||||
|
||||
size_t SharedMemory::SystemPageSize() { return sysconf(_SC_PAGESIZE); }
|
||||
|
||||
} // namespace mozilla::ipc
|
||||
@@ -1,221 +0,0 @@
|
||||
/* -*- 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 "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <mach/vm_map.h>
|
||||
#include <mach/mach_port.h>
|
||||
#if defined(XP_IOS)
|
||||
# include <mach/vm_map.h>
|
||||
# define mach_vm_address_t vm_address_t
|
||||
# define mach_vm_map vm_map
|
||||
# define mach_vm_read vm_read
|
||||
# define mach_vm_region_recurse vm_region_recurse_64
|
||||
# define mach_vm_size_t vm_size_t
|
||||
#else
|
||||
# include <mach/mach_vm.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h> // mprotect
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(XP_MACOSX) && defined(__x86_64__)
|
||||
# include "prenv.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/Printf.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
# define LOG_ERROR(str, args...) \
|
||||
PR_BEGIN_MACRO \
|
||||
mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ##args); \
|
||||
NS_WARNING(msg.get()); \
|
||||
PR_END_MACRO
|
||||
#else
|
||||
# define LOG_ERROR(str, args...) \
|
||||
do { /* nothing */ \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
static inline void* toPointer(mach_vm_address_t address) {
|
||||
return reinterpret_cast<void*>(static_cast<uintptr_t>(address));
|
||||
}
|
||||
|
||||
static inline mach_vm_address_t toVMAddress(void* pointer) {
|
||||
return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer));
|
||||
}
|
||||
|
||||
void SharedMemory::ResetImpl() {};
|
||||
|
||||
bool SharedMemory::CreateImpl(size_t size, bool freezable) {
|
||||
memory_object_size_t memoryObjectSize = round_page(size);
|
||||
|
||||
kern_return_t kr =
|
||||
mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
|
||||
MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
|
||||
getter_Transfers(mHandle), MACH_PORT_NULL);
|
||||
if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) {
|
||||
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size,
|
||||
mach_error_string(kr), kr);
|
||||
TakeHandle();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Maybe<void*> MapMemory(size_t size, void* fixedAddress,
|
||||
const mozilla::UniqueMachSendRight& port,
|
||||
bool readOnly) {
|
||||
kern_return_t kr;
|
||||
mach_vm_address_t address = toVMAddress(fixedAddress);
|
||||
|
||||
vm_prot_t vmProtection = VM_PROT_READ;
|
||||
if (!readOnly) {
|
||||
vmProtection |= VM_PROT_WRITE;
|
||||
}
|
||||
|
||||
kr =
|
||||
mach_vm_map(mach_task_self(), &address, round_page(size), 0,
|
||||
fixedAddress ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE, port.get(),
|
||||
0, false, vmProtection, vmProtection, VM_INHERIT_NONE);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
if (!fixedAddress) {
|
||||
LOG_ERROR(
|
||||
"Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
|
||||
size, mach_task_self(), mach_port_t(port.get()),
|
||||
mach_error_string(kr), kr);
|
||||
}
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
if (fixedAddress && fixedAddress != toPointer(address)) {
|
||||
kr = vm_deallocate(mach_task_self(), address, size);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
LOG_ERROR(
|
||||
"Failed to unmap shared memory at unsuitable address "
|
||||
"(%zu bytes) from %x, port %x. %s (%x)\n",
|
||||
size, mach_task_self(), mach_port_t(port.get()),
|
||||
mach_error_string(kr), kr);
|
||||
}
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(toPointer(address));
|
||||
}
|
||||
|
||||
Maybe<void*> SharedMemory::MapImpl(size_t size, void* fixedAddress) {
|
||||
return MapMemory(size, fixedAddress, mHandle, mReadOnly);
|
||||
}
|
||||
|
||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
||||
mach_vm_address_t address = 0;
|
||||
size = round_page(size);
|
||||
if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE,
|
||||
MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE, VM_PROT_NONE,
|
||||
VM_INHERIT_NONE) != KERN_SUCCESS ||
|
||||
vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
|
||||
return nullptr;
|
||||
}
|
||||
return toPointer(address);
|
||||
}
|
||||
|
||||
auto SharedMemory::CloneHandle(const Handle& aHandle) -> Handle {
|
||||
return mozilla::RetainMachSendRight(aHandle.get());
|
||||
}
|
||||
|
||||
void SharedMemory::UnmapImpl(size_t nBytes, void* address) {
|
||||
vm_address_t vm_address = toVMAddress(address);
|
||||
kern_return_t kr =
|
||||
vm_deallocate(mach_task_self(), vm_address, round_page(nBytes));
|
||||
if (kr != KERN_SUCCESS) {
|
||||
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
|
||||
mach_error_string(kr), kr);
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<SharedMemory::Handle> SharedMemory::ReadOnlyCopyImpl() {
|
||||
memory_object_size_t memoryObjectSize = round_page(mAllocSize);
|
||||
|
||||
mozilla::UniqueMachSendRight port;
|
||||
|
||||
void* address = mMemory.get();
|
||||
bool unmap = false;
|
||||
|
||||
if (!address) {
|
||||
// Temporarily map memory (as readonly) to get an address.
|
||||
if (auto memory = MapMemory(memoryObjectSize, nullptr, mHandle, true)) {
|
||||
address = *memory;
|
||||
unmap = true;
|
||||
} else {
|
||||
return Nothing();
|
||||
}
|
||||
}
|
||||
|
||||
kern_return_t kr = mach_make_memory_entry_64(
|
||||
mach_task_self(), &memoryObjectSize,
|
||||
static_cast<memory_object_offset_t>(reinterpret_cast<uintptr_t>(address)),
|
||||
VM_PROT_READ, getter_Transfers(port), MACH_PORT_NULL);
|
||||
|
||||
if (unmap) {
|
||||
kern_return_t kr =
|
||||
vm_deallocate(mach_task_self(), toVMAddress(address), memoryObjectSize);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
|
||||
mach_error_string(kr), kr);
|
||||
}
|
||||
}
|
||||
|
||||
if (kr != KERN_SUCCESS || memoryObjectSize < round_page(mAllocSize)) {
|
||||
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", mAllocSize,
|
||||
mach_error_string(kr), kr);
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(std::move(port));
|
||||
}
|
||||
|
||||
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
||||
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
||||
MOZ_CRASH("can't mprotect()");
|
||||
}
|
||||
}
|
||||
|
||||
bool SharedMemory::SystemProtectFallible(char* aAddr, size_t aSize,
|
||||
int aRights) {
|
||||
int flags = 0;
|
||||
if (aRights & RightsRead) flags |= PROT_READ;
|
||||
if (aRights & RightsWrite) flags |= PROT_WRITE;
|
||||
if (RightsNone == aRights) flags = PROT_NONE;
|
||||
|
||||
return 0 == mprotect(aAddr, aSize, flags);
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX) && defined(__x86_64__)
|
||||
std::atomic<size_t> sPageSizeOverride = 0;
|
||||
#endif
|
||||
|
||||
size_t SharedMemory::SystemPageSize() {
|
||||
#if defined(XP_MACOSX) && defined(__x86_64__)
|
||||
if (sPageSizeOverride == 0) {
|
||||
if (PR_GetEnv("MOZ_SHMEM_PAGESIZE_16K")) {
|
||||
sPageSizeOverride = 16 * 1024;
|
||||
} else {
|
||||
sPageSizeOverride = sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
}
|
||||
return sPageSizeOverride;
|
||||
#else
|
||||
return sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace mozilla::ipc
|
||||
@@ -4,418 +4,21 @@
|
||||
* 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/. */
|
||||
|
||||
/* This source code was derived from Chromium code, and as such is also subject
|
||||
* to the [Chromium license](ipc/chromium/src/LICENSE). */
|
||||
#include <sys/mman.h> // mprotect
|
||||
#include <unistd.h> // sysconf
|
||||
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef XP_LINUX
|
||||
# include "base/linux_memfd_defs.h"
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
# include "mozilla/WidgetUtilsGtk.h"
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
# include <sys/capsicum.h>
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_VALGRIND
|
||||
# include <valgrind/valgrind.h>
|
||||
#endif
|
||||
|
||||
#include "base/eintr_wrapper.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/string_util.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/ProfilerThreadSleep.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#if defined(XP_MACOSX) && defined(__x86_64__)
|
||||
# include "prenv.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
void SharedMemory::ResetImpl() {
|
||||
if (mFrozenFile) {
|
||||
CHROMIUM_LOG(WARNING) << "freezable shared memory was never frozen";
|
||||
mFrozenFile = nullptr;
|
||||
}
|
||||
mIsMemfd = false;
|
||||
};
|
||||
|
||||
SharedMemory::Handle SharedMemory::CloneHandle(const Handle& aHandle) {
|
||||
const int new_fd = dup(aHandle.get());
|
||||
if (new_fd < 0) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to duplicate file descriptor: "
|
||||
<< strerror(errno);
|
||||
return nullptr;
|
||||
}
|
||||
return mozilla::UniqueFileHandle(new_fd);
|
||||
}
|
||||
|
||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
||||
void* memory = mmap(nullptr, size, PROT_NONE,
|
||||
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
|
||||
if (memory == MAP_FAILED) {
|
||||
return nullptr;
|
||||
}
|
||||
munmap(memory, size);
|
||||
return memory;
|
||||
}
|
||||
|
||||
Maybe<void*> SharedMemory::MapImpl(size_t nBytes, void* fixedAddress) {
|
||||
// Don't use MAP_FIXED when a fixed_address was specified, since that can
|
||||
// replace pages that are alread mapped at that address.
|
||||
void* mem =
|
||||
mmap(fixedAddress, nBytes, PROT_READ | (mReadOnly ? 0 : PROT_WRITE),
|
||||
MAP_SHARED, mHandle.get(), 0);
|
||||
|
||||
if (mem == MAP_FAILED) {
|
||||
CHROMIUM_LOG(WARNING) << "Call to mmap failed: " << strerror(errno);
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
if (fixedAddress && mem != fixedAddress) {
|
||||
bool munmap_succeeded = munmap(mem, nBytes) == 0;
|
||||
DCHECK(munmap_succeeded) << "Call to munmap failed, errno=" << errno;
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(mem);
|
||||
}
|
||||
|
||||
void SharedMemory::UnmapImpl(size_t nBytes, void* address) {
|
||||
munmap(address, nBytes);
|
||||
}
|
||||
|
||||
// memfd_create is a nonstandard interface for creating anonymous
|
||||
// shared memory accessible as a file descriptor but not tied to any
|
||||
// filesystem. It first appeared in Linux 3.17, and was adopted by
|
||||
// FreeBSD in version 13.
|
||||
|
||||
#if !defined(HAVE_MEMFD_CREATE) && defined(XP_LINUX) && \
|
||||
defined(SYS_memfd_create)
|
||||
|
||||
// Older libc versions (e.g., glibc before 2.27) don't have the
|
||||
// wrapper, but we can supply our own; see `linux_memfd_defs.h`.
|
||||
|
||||
static int memfd_create(const char* name, unsigned int flags) {
|
||||
return syscall(SYS_memfd_create, name, flags);
|
||||
}
|
||||
|
||||
# define HAVE_MEMFD_CREATE 1
|
||||
#if defined(XP_MACOSX) && defined(__x86_64__)
|
||||
std::atomic<size_t> sPageSizeOverride = 0;
|
||||
#endif
|
||||
|
||||
// memfd supports having "seals" applied to the file, to prevent
|
||||
// various types of changes (which apply to all fds referencing the
|
||||
// file). Unfortunately, we can't rely on F_SEAL_WRITE to implement
|
||||
// Freeze(); see the comments in ReadOnlyCopy() below.
|
||||
//
|
||||
// Instead, to prevent a child process from regaining write access to
|
||||
// a read-only copy, the OS must also provide a way to remove write
|
||||
// permissions at the file descriptor level. This next section
|
||||
// attempts to accomplish that.
|
||||
|
||||
#ifdef HAVE_MEMFD_CREATE
|
||||
# ifdef XP_LINUX
|
||||
# define USE_MEMFD_CREATE 1
|
||||
|
||||
// To create a read-only duplicate of an fd, we can use procfs; the
|
||||
// same operation could restore write access, but sandboxing prevents
|
||||
// child processes from accessing /proc.
|
||||
//
|
||||
// (Note: if this ever changes to not use /proc, also reconsider how
|
||||
// and if HaveMemfd should check whether this works.)
|
||||
|
||||
static int DupReadOnly(int fd) {
|
||||
std::string path = StringPrintf("/proc/self/fd/%d", fd);
|
||||
// procfs opens probably won't EINTR, but checking for it can't hurt
|
||||
return HANDLE_EINTR(open(path.c_str(), O_RDONLY | O_CLOEXEC));
|
||||
}
|
||||
|
||||
# elif defined(__FreeBSD__)
|
||||
# define USE_MEMFD_CREATE 1
|
||||
|
||||
// FreeBSD's Capsicum framework allows irrevocably restricting the
|
||||
// operations permitted on a file descriptor.
|
||||
|
||||
static int DupReadOnly(int fd) {
|
||||
int rofd = dup(fd);
|
||||
if (rofd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cap_rights_t rights;
|
||||
cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R);
|
||||
if (cap_rights_limit(rofd, &rights) < 0) {
|
||||
int err = errno;
|
||||
close(rofd);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rofd;
|
||||
}
|
||||
|
||||
# else // unhandled OS
|
||||
# warning "OS has memfd_create but no DupReadOnly implementation"
|
||||
# endif // OS selection
|
||||
#endif // HAVE_MEMFD_CREATE
|
||||
|
||||
// Runtime detection for memfd support.
|
||||
static bool HaveMemfd() {
|
||||
#ifdef USE_MEMFD_CREATE
|
||||
static const bool kHave = [] {
|
||||
mozilla::UniqueFileHandle fd(
|
||||
memfd_create("mozilla-ipc-test", MFD_CLOEXEC | MFD_ALLOW_SEALING));
|
||||
if (!fd) {
|
||||
DCHECK_EQ(errno, ENOSYS);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify that DupReadOnly works; on Linux it's known to fail if:
|
||||
//
|
||||
// * SELinux assigns the memfd a type for which this process's
|
||||
// domain doesn't have "open" permission; this is always the
|
||||
// case on Android but could occur on desktop as well
|
||||
//
|
||||
// * /proc (used by the DupReadOnly implementation) isn't mounted,
|
||||
// which is a configuration that the Tor Browser project is
|
||||
// interested in as a way to reduce fingerprinting risk
|
||||
//
|
||||
// Sandboxed processes on Linux also can't use it if sandboxing
|
||||
// has already been started, but that's expected. It should be
|
||||
// safe for sandboxed child processes to use memfd even if an
|
||||
// unsandboxed process couldn't freeze them, because freezing
|
||||
// isn't allowed (or meaningful) for memory created by another
|
||||
// process.
|
||||
|
||||
if (!PR_GetEnv("MOZ_SANDBOXED")) {
|
||||
mozilla::UniqueFileHandle rofd(DupReadOnly(fd.get()));
|
||||
if (!rofd) {
|
||||
CHROMIUM_LOG(WARNING) << "read-only dup failed (" << strerror(errno)
|
||||
<< "); not using memfd";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
return kHave;
|
||||
#else
|
||||
return false;
|
||||
#endif // USE_MEMFD_CREATE
|
||||
}
|
||||
|
||||
// static
|
||||
bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid) {
|
||||
if (HaveMemfd()) {
|
||||
return false;
|
||||
}
|
||||
*str += '/';
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
// The Snap package environment doesn't provide a private /dev/shm
|
||||
// (it's used for communication with services like PulseAudio);
|
||||
// instead AppArmor is used to restrict access to it. Anything with
|
||||
// this prefix is allowed:
|
||||
if (const char* snap = mozilla::widget::GetSnapInstanceName()) {
|
||||
StringAppendF(str, "snap.%s.", snap);
|
||||
}
|
||||
#endif // XP_LINUX
|
||||
// Hopefully the "implementation defined" name length limit is long
|
||||
// enough for this.
|
||||
StringAppendF(str, "org.mozilla.ipc.%d.", static_cast<int>(pid));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::CreateImpl(size_t size, bool freezable) {
|
||||
DCHECK(size > 0);
|
||||
DCHECK(!mHandle);
|
||||
DCHECK(!mFrozenFile);
|
||||
|
||||
mozilla::UniqueFileHandle fd;
|
||||
mozilla::UniqueFileHandle frozen_fd;
|
||||
bool is_memfd = false;
|
||||
|
||||
#ifdef USE_MEMFD_CREATE
|
||||
if (HaveMemfd()) {
|
||||
const unsigned flags = MFD_CLOEXEC | (freezable ? MFD_ALLOW_SEALING : 0);
|
||||
fd.reset(memfd_create("mozilla-ipc", flags));
|
||||
if (!fd) {
|
||||
// In general it's too late to fall back here -- in a sandboxed
|
||||
// child process, shm_open is already blocked. And it shouldn't
|
||||
// be necessary.
|
||||
CHROMIUM_LOG(WARNING) << "failed to create memfd: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
is_memfd = true;
|
||||
if (freezable) {
|
||||
frozen_fd.reset(DupReadOnly(fd.get()));
|
||||
if (!frozen_fd) {
|
||||
CHROMIUM_LOG(WARNING)
|
||||
<< "failed to create read-only memfd: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!fd) {
|
||||
// Generic Unix: shm_open + shm_unlink
|
||||
do {
|
||||
// The names don't need to be unique, but it saves time if they
|
||||
// usually are.
|
||||
static mozilla::Atomic<size_t> sNameCounter;
|
||||
std::string name;
|
||||
CHECK(AppendPosixShmPrefix(&name, getpid()));
|
||||
StringAppendF(&name, "%zu", sNameCounter++);
|
||||
// O_EXCL means the names being predictable shouldn't be a problem.
|
||||
fd.reset(HANDLE_EINTR(
|
||||
shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)));
|
||||
if (fd) {
|
||||
if (freezable) {
|
||||
frozen_fd.reset(HANDLE_EINTR(shm_open(name.c_str(), O_RDONLY, 0400)));
|
||||
if (!frozen_fd) {
|
||||
int open_err = errno;
|
||||
shm_unlink(name.c_str());
|
||||
DLOG(FATAL) << "failed to re-open freezable shm: "
|
||||
<< strerror(open_err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (shm_unlink(name.c_str()) != 0) {
|
||||
// This shouldn't happen, but if it does: assume the file is
|
||||
// in fact leaked, and bail out now while it's still 0-length.
|
||||
DLOG(FATAL) << "failed to unlink shm: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (!fd && errno == EEXIST);
|
||||
}
|
||||
|
||||
if (!fd) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::Maybe<int> fallocateError;
|
||||
#if defined(HAVE_POSIX_FALLOCATE)
|
||||
// Using posix_fallocate will ensure that there's actually space for this
|
||||
// file. Otherwise we end up with a sparse file that can give SIGBUS if we
|
||||
// run out of space while writing to it. (This doesn't apply to memfd.)
|
||||
if (!is_memfd) {
|
||||
int rv;
|
||||
// Avoid repeated interruptions of posix_fallocate by the profiler's
|
||||
// SIGPROF sampling signal. Indicating "thread sleep" here means we'll
|
||||
// get up to one interruption but not more. See bug 1658847 for more.
|
||||
// This has to be scoped outside the HANDLE_RV_EINTR retry loop.
|
||||
{
|
||||
AUTO_PROFILER_THREAD_SLEEP;
|
||||
|
||||
rv = HANDLE_RV_EINTR(
|
||||
posix_fallocate(fd.get(), 0, static_cast<off_t>(size)));
|
||||
}
|
||||
|
||||
// Some filesystems have trouble with posix_fallocate. For now, we must
|
||||
// fallback ftruncate and accept the allocation failures like we do
|
||||
// without posix_fallocate.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1618914
|
||||
if (rv != 0 && rv != EOPNOTSUPP && rv != EINVAL && rv != ENODEV) {
|
||||
CHROMIUM_LOG(WARNING)
|
||||
<< "fallocate failed to set shm size: " << strerror(rv);
|
||||
return false;
|
||||
}
|
||||
fallocateError = mozilla::Some(rv);
|
||||
}
|
||||
#endif
|
||||
|
||||
// If posix_fallocate isn't supported / relevant for this type of
|
||||
// file (either failed with an expected error, or wasn't attempted),
|
||||
// then set the size with ftruncate:
|
||||
if (fallocateError != mozilla::Some(0)) {
|
||||
int rv = HANDLE_EINTR(ftruncate(fd.get(), static_cast<off_t>(size)));
|
||||
if (rv != 0) {
|
||||
int ftruncate_errno = errno;
|
||||
if (fallocateError) {
|
||||
CHROMIUM_LOG(WARNING) << "fallocate failed to set shm size: "
|
||||
<< strerror(*fallocateError);
|
||||
}
|
||||
CHROMIUM_LOG(WARNING)
|
||||
<< "ftruncate failed to set shm size: " << strerror(ftruncate_errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mHandle = std::move(fd);
|
||||
mFrozenFile = std::move(frozen_fd);
|
||||
mIsMemfd = is_memfd;
|
||||
return true;
|
||||
}
|
||||
|
||||
Maybe<SharedMemory::Handle> SharedMemory::ReadOnlyCopyImpl() {
|
||||
#ifdef USE_MEMFD_CREATE
|
||||
# ifdef MOZ_VALGRIND
|
||||
// Valgrind allows memfd_create but doesn't understand F_ADD_SEALS.
|
||||
static const bool haveSeals = RUNNING_ON_VALGRIND == 0;
|
||||
# else
|
||||
static const bool haveSeals = true;
|
||||
# endif
|
||||
static const bool useSeals = !PR_GetEnv("MOZ_SHM_NO_SEALS");
|
||||
if (mIsMemfd && haveSeals && useSeals) {
|
||||
// Seals are added to the file as defense-in-depth. The primary
|
||||
// method of access control is creating a read-only fd (using
|
||||
// procfs in this case) and requiring that sandboxes processes not
|
||||
// have access to /proc/self/fd to regain write permission; this
|
||||
// is the same as with shm_open.
|
||||
//
|
||||
// Unfortunately, F_SEAL_WRITE is unreliable: if the process
|
||||
// forked while there was a writeable mapping, it will inherit a
|
||||
// copy of the mapping, which causes the seal to fail.
|
||||
//
|
||||
// (Also, in the future we may want to split this into separate
|
||||
// classes for mappings and shared memory handles, which would
|
||||
// complicate identifying the case where `F_SEAL_WRITE` would be
|
||||
// possible even in the absence of races with fork.)
|
||||
//
|
||||
// However, Linux 5.1 added F_SEAL_FUTURE_WRITE, which prevents
|
||||
// write operations afterwards, but existing writeable mappings
|
||||
// are unaffected (similar to ashmem protection semantics).
|
||||
|
||||
const int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL;
|
||||
int sealError = EINVAL;
|
||||
|
||||
# ifdef F_SEAL_FUTURE_WRITE
|
||||
sealError =
|
||||
fcntl(mHandle.get(), F_ADD_SEALS, seals | F_SEAL_FUTURE_WRITE) == 0
|
||||
? 0
|
||||
: errno;
|
||||
# endif // F_SEAL_FUTURE_WRITE
|
||||
if (sealError == EINVAL) {
|
||||
sealError = fcntl(mHandle.get(), F_ADD_SEALS, seals) == 0 ? 0 : errno;
|
||||
}
|
||||
if (sealError != 0) {
|
||||
CHROMIUM_LOG(WARNING) << "failed to seal memfd: " << strerror(errno);
|
||||
return Nothing();
|
||||
}
|
||||
}
|
||||
#else // !USE_MEMFD_CREATE
|
||||
DCHECK(!mIsMemfd);
|
||||
#endif
|
||||
|
||||
DCHECK(mFrozenFile);
|
||||
DCHECK(mHandle);
|
||||
mozilla::UniqueFileHandle ro_file = std::move(mFrozenFile);
|
||||
|
||||
DCHECK(ro_file);
|
||||
|
||||
return Some(std::move(ro_file));
|
||||
}
|
||||
|
||||
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
||||
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
||||
MOZ_CRASH("can't mprotect()");
|
||||
@@ -432,8 +35,19 @@ bool SharedMemory::SystemProtectFallible(char* aAddr, size_t aSize,
|
||||
return 0 == mprotect(aAddr, aSize, flags);
|
||||
}
|
||||
|
||||
size_t SharedMemory::SystemPageSize() { return sysconf(_SC_PAGESIZE); }
|
||||
|
||||
bool SharedMemory::UsingPosixShm() { return !HaveMemfd(); }
|
||||
size_t SharedMemory::SystemPageSize() {
|
||||
#if defined(XP_MACOSX) && defined(__x86_64__)
|
||||
if (sPageSizeOverride == 0) {
|
||||
if (PR_GetEnv("MOZ_SHMEM_PAGESIZE_16K")) {
|
||||
sPageSizeOverride = 16 * 1024;
|
||||
} else {
|
||||
sPageSizeOverride = sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
}
|
||||
return sPageSizeOverride;
|
||||
#else
|
||||
return sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace mozilla::ipc
|
||||
|
||||
@@ -4,211 +4,12 @@
|
||||
* 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/. */
|
||||
|
||||
/* This source code was derived from Chromium code, and as such is also subject
|
||||
* to the [Chromium license](ipc/chromium/src/LICENSE). */
|
||||
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/win_util.h"
|
||||
#include "base/string_util.h"
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/RandomNum.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsString.h"
|
||||
#ifdef MOZ_MEMORY
|
||||
# include "mozmemory_utils.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
// NtQuerySection is an internal (but believed to be stable) API and the
|
||||
// structures it uses are defined in nt_internals.h.
|
||||
// So we have to define them ourselves.
|
||||
typedef enum _SECTION_INFORMATION_CLASS {
|
||||
SectionBasicInformation,
|
||||
} SECTION_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _SECTION_BASIC_INFORMATION {
|
||||
PVOID BaseAddress;
|
||||
ULONG Attributes;
|
||||
LARGE_INTEGER Size;
|
||||
} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
|
||||
|
||||
typedef ULONG(__stdcall* NtQuerySectionType)(
|
||||
HANDLE SectionHandle, SECTION_INFORMATION_CLASS SectionInformationClass,
|
||||
PVOID SectionInformation, ULONG SectionInformationLength,
|
||||
PULONG ResultLength);
|
||||
|
||||
// Checks if the section object is safe to map. At the moment this just means
|
||||
// it's not an image section.
|
||||
bool IsSectionSafeToMap(HANDLE handle) {
|
||||
static NtQuerySectionType nt_query_section_func =
|
||||
reinterpret_cast<NtQuerySectionType>(
|
||||
::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
|
||||
DCHECK(nt_query_section_func);
|
||||
|
||||
// The handle must have SECTION_QUERY access for this to succeed.
|
||||
SECTION_BASIC_INFORMATION basic_information = {};
|
||||
ULONG status =
|
||||
nt_query_section_func(handle, SectionBasicInformation, &basic_information,
|
||||
sizeof(basic_information), nullptr);
|
||||
if (status) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mozilla::ipc {
|
||||
|
||||
void SharedMemory::ResetImpl() {};
|
||||
|
||||
SharedMemory::Handle SharedMemory::CloneHandle(const Handle& aHandle) {
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
if (DuplicateHandle(GetCurrentProcess(), aHandle.get(), GetCurrentProcess(),
|
||||
&handle, 0, false, DUPLICATE_SAME_ACCESS)) {
|
||||
return SharedMemoryHandle(handle);
|
||||
}
|
||||
NS_WARNING("DuplicateHandle Failed!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
||||
void* memory = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
if (memory) {
|
||||
VirtualFree(memory, 0, MEM_RELEASE);
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
Maybe<void*> SharedMemory::MapImpl(size_t nBytes, void* fixedAddress) {
|
||||
if (mExternalHandle && !IsSectionSafeToMap(mHandle.get())) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
void* mem = MapViewOfFileEx(
|
||||
mHandle.get(), mReadOnly ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
|
||||
0, 0, nBytes, fixedAddress);
|
||||
if (mem) {
|
||||
MOZ_ASSERT(!fixedAddress || mem == fixedAddress,
|
||||
"MapViewOfFileEx returned an expected address");
|
||||
return Some(mem);
|
||||
}
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
void SharedMemory::UnmapImpl(size_t nBytes, void* address) {
|
||||
UnmapViewOfFile(address);
|
||||
}
|
||||
|
||||
// Wrapper around CreateFileMappingW for pagefile-backed regions. When out of
|
||||
// memory, may attempt to stall and retry rather than returning immediately, in
|
||||
// hopes that the page file is about to be expanded by Windows. (bug 1822383,
|
||||
// bug 1716727)
|
||||
//
|
||||
// This method is largely a copy of the MozVirtualAlloc method from
|
||||
// mozjemalloc.cpp, which implements this strategy for VirtualAlloc calls,
|
||||
// except re-purposed to handle CreateFileMapping.
|
||||
static HANDLE MozCreateFileMappingW(
|
||||
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect,
|
||||
DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName) {
|
||||
#ifdef MOZ_MEMORY
|
||||
constexpr auto IsOOMError = [] {
|
||||
return ::GetLastError() == ERROR_COMMITMENT_LIMIT;
|
||||
};
|
||||
|
||||
{
|
||||
HANDLE handle = ::CreateFileMappingW(
|
||||
INVALID_HANDLE_VALUE, lpFileMappingAttributes, flProtect,
|
||||
dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
|
||||
if (MOZ_LIKELY(handle)) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(handle != INVALID_HANDLE_VALUE,
|
||||
"::CreateFileMapping should return NULL, not "
|
||||
"INVALID_HANDLE_VALUE, on failure");
|
||||
return handle;
|
||||
}
|
||||
|
||||
// We can't do anything for errors other than OOM.
|
||||
if (!IsOOMError()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Retry as many times as desired (possibly zero).
|
||||
const mozilla::StallSpecs stallSpecs = mozilla::GetAllocatorStallSpecs();
|
||||
|
||||
const auto ret =
|
||||
stallSpecs.StallAndRetry(&::Sleep, [&]() -> std::optional<HANDLE> {
|
||||
HANDLE handle = ::CreateFileMappingW(
|
||||
INVALID_HANDLE_VALUE, lpFileMappingAttributes, flProtect,
|
||||
dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
|
||||
|
||||
if (handle) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(handle != INVALID_HANDLE_VALUE,
|
||||
"::CreateFileMapping should return NULL, not "
|
||||
"INVALID_HANDLE_VALUE, on failure");
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Failure for some reason other than OOM.
|
||||
if (!IsOOMError()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
return ret.value_or(nullptr);
|
||||
#else
|
||||
return ::CreateFileMappingW(INVALID_HANDLE_VALUE, lpFileMappingAttributes,
|
||||
flProtect, dwMaximumSizeHigh, dwMaximumSizeLow,
|
||||
lpName);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SharedMemory::CreateImpl(size_t size, bool freezable) {
|
||||
// If the shared memory object has no DACL, any process can
|
||||
// duplicate its handles with any access rights; e.g., re-add write
|
||||
// access to a read-only handle. To prevent that, we give it an
|
||||
// empty DACL, so that no process can do that.
|
||||
SECURITY_ATTRIBUTES sa, *psa = nullptr;
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
ACL dacl;
|
||||
|
||||
if (freezable) {
|
||||
psa = &sa;
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
sa.bInheritHandle = FALSE;
|
||||
|
||||
if (NS_WARN_IF(!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) ||
|
||||
NS_WARN_IF(
|
||||
!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) ||
|
||||
NS_WARN_IF(!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mHandle.reset(MozCreateFileMappingW(psa, PAGE_READWRITE, 0,
|
||||
static_cast<DWORD>(size), nullptr));
|
||||
return (bool)mHandle;
|
||||
}
|
||||
|
||||
Maybe<SharedMemory::Handle> SharedMemory::ReadOnlyCopyImpl() {
|
||||
HANDLE ro_handle;
|
||||
if (!::DuplicateHandle(GetCurrentProcess(), mHandle.get(),
|
||||
GetCurrentProcess(), &ro_handle,
|
||||
GENERIC_READ | FILE_MAP_READ, false, 0)) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(ro_handle);
|
||||
}
|
||||
|
||||
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
||||
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
||||
MOZ_CRASH("can't VirtualProtect()");
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/process.h"
|
||||
#include "chrome/common/ipc_message_utils.h"
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
@@ -79,7 +79,14 @@ EXPORTS.mozilla.ipc += [
|
||||
]
|
||||
|
||||
if CONFIG["OS_ARCH"] == "WINNT":
|
||||
SOURCES += ["WindowsMessageLoop.cpp"]
|
||||
SOURCES += [
|
||||
"SharedMemory_windows.cpp",
|
||||
"WindowsMessageLoop.cpp",
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
"SharedMemory_posix.cpp",
|
||||
]
|
||||
|
||||
if CONFIG["OS_ARCH"] == "WINNT":
|
||||
SOURCES += [
|
||||
@@ -108,14 +115,11 @@ else:
|
||||
]
|
||||
|
||||
if CONFIG["OS_ARCH"] == "Darwin":
|
||||
SOURCES += ["SharedMemory_mach.cpp"]
|
||||
elif CONFIG["OS_ARCH"] == "WINNT":
|
||||
SOURCES += ["SharedMemory_windows.cpp"]
|
||||
elif CONFIG["OS_TARGET"] == "Android":
|
||||
SOURCES += ["SharedMemory_android.cpp"]
|
||||
EXPORTS.mozilla.ipc += ["SharedMemoryImpl_mach.h"]
|
||||
SOURCES += ["SharedMemoryImpl_mach.cpp"]
|
||||
else:
|
||||
SOURCES += ["SharedMemory_posix.cpp"]
|
||||
|
||||
EXPORTS.mozilla.ipc += ["SharedMemoryImpl_chromium.h"]
|
||||
SOURCES += ["SharedMemoryImpl_chromium.cpp"]
|
||||
|
||||
if CONFIG["OS_ARCH"] == "Linux":
|
||||
UNIFIED_SOURCES += [
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
@@ -28,29 +30,28 @@ namespace mozilla {
|
||||
// compromised and then receives a frozen handle.
|
||||
TEST(IPCSharedMemory, FreezeAndMapRW)
|
||||
{
|
||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
||||
base::SharedMemory shm;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shm->CreateFreezable(1));
|
||||
ASSERT_TRUE(shm->Map(1));
|
||||
auto* mem = reinterpret_cast<char*>(shm->Memory());
|
||||
ASSERT_TRUE(shm.CreateFreezeable(1));
|
||||
ASSERT_TRUE(shm.Map(1));
|
||||
auto mem = reinterpret_cast<char*>(shm.memory());
|
||||
ASSERT_TRUE(mem);
|
||||
*mem = 'A';
|
||||
|
||||
// Freeze
|
||||
ASSERT_TRUE(shm->Freeze());
|
||||
ASSERT_FALSE(shm->Memory());
|
||||
ASSERT_TRUE(shm.Freeze());
|
||||
ASSERT_FALSE(shm.memory());
|
||||
|
||||
// Re-create as writeable
|
||||
auto handle = shm->TakeHandleAndUnmap();
|
||||
ASSERT_TRUE(shm->IsHandleValid(handle));
|
||||
ASSERT_FALSE(shm->IsValid());
|
||||
ASSERT_TRUE(shm->SetHandle(std::move(handle),
|
||||
ipc::SharedMemory::OpenRights::RightsReadWrite));
|
||||
ASSERT_TRUE(shm->IsValid());
|
||||
auto handle = shm.TakeHandle();
|
||||
ASSERT_TRUE(shm.IsHandleValid(handle));
|
||||
ASSERT_FALSE(shm.IsValid());
|
||||
ASSERT_TRUE(shm.SetHandle(std::move(handle), /* read-only */ false));
|
||||
ASSERT_TRUE(shm.IsValid());
|
||||
|
||||
// This should fail
|
||||
EXPECT_FALSE(shm->Map(1));
|
||||
EXPECT_FALSE(shm.Map(1));
|
||||
}
|
||||
|
||||
// Try to restore write permissions to a frozen mapping. Threat
|
||||
@@ -59,22 +60,22 @@ TEST(IPCSharedMemory, FreezeAndMapRW)
|
||||
// proof-of-concept at https://crbug.com/project-zero/1671 ).
|
||||
TEST(IPCSharedMemory, FreezeAndReprotect)
|
||||
{
|
||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
||||
base::SharedMemory shm;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shm->CreateFreezable(1));
|
||||
ASSERT_TRUE(shm->Map(1));
|
||||
auto* mem = reinterpret_cast<char*>(shm->Memory());
|
||||
ASSERT_TRUE(shm.CreateFreezeable(1));
|
||||
ASSERT_TRUE(shm.Map(1));
|
||||
auto mem = reinterpret_cast<char*>(shm.memory());
|
||||
ASSERT_TRUE(mem);
|
||||
*mem = 'A';
|
||||
|
||||
// Freeze
|
||||
ASSERT_TRUE(shm->Freeze());
|
||||
ASSERT_FALSE(shm->Memory());
|
||||
ASSERT_TRUE(shm.Freeze());
|
||||
ASSERT_FALSE(shm.memory());
|
||||
|
||||
// Re-map
|
||||
ASSERT_TRUE(shm->Map(1));
|
||||
mem = reinterpret_cast<char*>(shm->Memory());
|
||||
ASSERT_TRUE(shm.Map(1));
|
||||
mem = reinterpret_cast<char*>(shm.memory());
|
||||
ASSERT_EQ(*mem, 'A');
|
||||
|
||||
// Try to alter protection; should fail
|
||||
@@ -82,39 +83,32 @@ TEST(IPCSharedMemory, FreezeAndReprotect)
|
||||
mem, 1, ipc::SharedMemory::RightsReadWrite));
|
||||
}
|
||||
|
||||
#if !defined(XP_WIN) && !defined(XP_DARWIN)
|
||||
#ifndef XP_WIN
|
||||
// This essentially tests whether FreezeAndReprotect would have failed
|
||||
// without the freeze.
|
||||
//
|
||||
// It doesn't work on Windows: VirtualProtect can't exceed the permissions set
|
||||
// in MapViewOfFile regardless of the security status of the original handle.
|
||||
//
|
||||
// It doesn't work on MacOS: we can set a higher max_protection for the memory
|
||||
// when creating the handle, but we wouldn't want to do this for freezable
|
||||
// handles (to prevent creating additional RW mappings that break the memory
|
||||
// freezing invariants).
|
||||
// without the freeze. It doesn't work on Windows: VirtualProtect
|
||||
// can't exceed the permissions set in MapViewOfFile regardless of the
|
||||
// security status of the original handle.
|
||||
TEST(IPCSharedMemory, Reprotect)
|
||||
{
|
||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
||||
base::SharedMemory shm;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shm->CreateFreezable(1));
|
||||
ASSERT_TRUE(shm->Map(1));
|
||||
auto* mem = reinterpret_cast<char*>(shm->Memory());
|
||||
ASSERT_TRUE(shm.CreateFreezeable(1));
|
||||
ASSERT_TRUE(shm.Map(1));
|
||||
auto mem = reinterpret_cast<char*>(shm.memory());
|
||||
ASSERT_TRUE(mem);
|
||||
*mem = 'A';
|
||||
|
||||
// Re-create as read-only
|
||||
auto handle = shm->TakeHandleAndUnmap();
|
||||
ASSERT_TRUE(shm->IsHandleValid(handle));
|
||||
ASSERT_FALSE(shm->IsValid());
|
||||
ASSERT_TRUE(shm->SetHandle(std::move(handle),
|
||||
ipc::SharedMemory::OpenRights::RightsReadOnly));
|
||||
ASSERT_TRUE(shm->IsValid());
|
||||
auto handle = shm.TakeHandle();
|
||||
ASSERT_TRUE(shm.IsHandleValid(handle));
|
||||
ASSERT_FALSE(shm.IsValid());
|
||||
ASSERT_TRUE(shm.SetHandle(std::move(handle), /* read-only */ true));
|
||||
ASSERT_TRUE(shm.IsValid());
|
||||
|
||||
// Re-map
|
||||
ASSERT_TRUE(shm->Map(1));
|
||||
mem = reinterpret_cast<char*>(shm->Memory());
|
||||
ASSERT_TRUE(shm.Map(1));
|
||||
mem = reinterpret_cast<char*>(shm.memory());
|
||||
ASSERT_EQ(*mem, 'A');
|
||||
|
||||
// Try to alter protection; should succeed, because not frozen
|
||||
@@ -129,23 +123,23 @@ TEST(IPCSharedMemory, Reprotect)
|
||||
// See also https://crbug.com/338538
|
||||
TEST(IPCSharedMemory, WinUnfreeze)
|
||||
{
|
||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
||||
base::SharedMemory shm;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shm->CreateFreezable(1));
|
||||
ASSERT_TRUE(shm->Map(1));
|
||||
auto* mem = reinterpret_cast<char*>(shm->Memory());
|
||||
ASSERT_TRUE(shm.CreateFreezeable(1));
|
||||
ASSERT_TRUE(shm.Map(1));
|
||||
auto mem = reinterpret_cast<char*>(shm.memory());
|
||||
ASSERT_TRUE(mem);
|
||||
*mem = 'A';
|
||||
|
||||
// Freeze
|
||||
ASSERT_TRUE(shm->Freeze());
|
||||
ASSERT_FALSE(shm->Memory());
|
||||
ASSERT_TRUE(shm.Freeze());
|
||||
ASSERT_FALSE(shm.memory());
|
||||
|
||||
// Extract handle.
|
||||
auto handle = shm->TakeHandleAndUnmap();
|
||||
ASSERT_TRUE(shm->IsHandleValid(handle));
|
||||
ASSERT_FALSE(shm->IsValid());
|
||||
auto handle = shm.TakeHandle();
|
||||
ASSERT_TRUE(shm.IsHandleValid(handle));
|
||||
ASSERT_FALSE(shm.IsValid());
|
||||
|
||||
// Unfreeze.
|
||||
HANDLE newHandle = INVALID_HANDLE_VALUE;
|
||||
@@ -160,25 +154,24 @@ TEST(IPCSharedMemory, WinUnfreeze)
|
||||
// mapping in the case that the page wasn't accessed before the copy.
|
||||
TEST(IPCSharedMemory, ROCopyAndWrite)
|
||||
{
|
||||
auto shmRW = MakeRefPtr<ipc::SharedMemory>();
|
||||
auto shmRO = MakeRefPtr<ipc::SharedMemory>();
|
||||
base::SharedMemory shmRW, shmRO;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shmRW->CreateFreezable(1));
|
||||
ASSERT_TRUE(shmRW->Map(1));
|
||||
auto* memRW = reinterpret_cast<char*>(shmRW->Memory());
|
||||
ASSERT_TRUE(shmRW.CreateFreezeable(1));
|
||||
ASSERT_TRUE(shmRW.Map(1));
|
||||
auto memRW = reinterpret_cast<char*>(shmRW.memory());
|
||||
ASSERT_TRUE(memRW);
|
||||
|
||||
// Create read-only copy
|
||||
ASSERT_TRUE(shmRW->ReadOnlyCopy(shmRO));
|
||||
EXPECT_FALSE(shmRW->IsValid());
|
||||
ASSERT_EQ(shmRW->Memory(), memRW);
|
||||
ASSERT_EQ(shmRO->MaxSize(), size_t(1));
|
||||
ASSERT_TRUE(shmRW.ReadOnlyCopy(&shmRO));
|
||||
EXPECT_FALSE(shmRW.IsValid());
|
||||
ASSERT_EQ(shmRW.memory(), memRW);
|
||||
ASSERT_EQ(shmRO.max_size(), size_t(1));
|
||||
|
||||
// Map read-only
|
||||
ASSERT_TRUE(shmRO->IsValid());
|
||||
ASSERT_TRUE(shmRO->Map(1));
|
||||
const auto* memRO = reinterpret_cast<const char*>(shmRO->Memory());
|
||||
ASSERT_TRUE(shmRO.IsValid());
|
||||
ASSERT_TRUE(shmRO.Map(1));
|
||||
auto memRO = reinterpret_cast<const char*>(shmRO.memory());
|
||||
ASSERT_TRUE(memRO);
|
||||
ASSERT_NE(memRW, memRO);
|
||||
|
||||
@@ -192,26 +185,25 @@ TEST(IPCSharedMemory, ROCopyAndWrite)
|
||||
// (and, before that, sees the state as of when the copy was made).
|
||||
TEST(IPCSharedMemory, ROCopyAndRewrite)
|
||||
{
|
||||
auto shmRW = MakeRefPtr<ipc::SharedMemory>();
|
||||
auto shmRO = MakeRefPtr<ipc::SharedMemory>();
|
||||
base::SharedMemory shmRW, shmRO;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shmRW->CreateFreezable(1));
|
||||
ASSERT_TRUE(shmRW->Map(1));
|
||||
auto* memRW = reinterpret_cast<char*>(shmRW->Memory());
|
||||
ASSERT_TRUE(shmRW.CreateFreezeable(1));
|
||||
ASSERT_TRUE(shmRW.Map(1));
|
||||
auto memRW = reinterpret_cast<char*>(shmRW.memory());
|
||||
ASSERT_TRUE(memRW);
|
||||
*memRW = 'A';
|
||||
|
||||
// Create read-only copy
|
||||
ASSERT_TRUE(shmRW->ReadOnlyCopy(shmRO));
|
||||
EXPECT_FALSE(shmRW->IsValid());
|
||||
ASSERT_EQ(shmRW->Memory(), memRW);
|
||||
ASSERT_EQ(shmRO->MaxSize(), size_t(1));
|
||||
ASSERT_TRUE(shmRW.ReadOnlyCopy(&shmRO));
|
||||
EXPECT_FALSE(shmRW.IsValid());
|
||||
ASSERT_EQ(shmRW.memory(), memRW);
|
||||
ASSERT_EQ(shmRO.max_size(), size_t(1));
|
||||
|
||||
// Map read-only
|
||||
ASSERT_TRUE(shmRO->IsValid());
|
||||
ASSERT_TRUE(shmRO->Map(1));
|
||||
const auto* memRO = reinterpret_cast<const char*>(shmRO->Memory());
|
||||
ASSERT_TRUE(shmRO.IsValid());
|
||||
ASSERT_TRUE(shmRO.Map(1));
|
||||
auto memRO = reinterpret_cast<const char*>(shmRO.memory());
|
||||
ASSERT_TRUE(memRO);
|
||||
ASSERT_NE(memRW, memRO);
|
||||
|
||||
@@ -225,52 +217,49 @@ TEST(IPCSharedMemory, ROCopyAndRewrite)
|
||||
// See FreezeAndMapRW.
|
||||
TEST(IPCSharedMemory, ROCopyAndMapRW)
|
||||
{
|
||||
auto shmRW = MakeRefPtr<ipc::SharedMemory>();
|
||||
auto shmRO = MakeRefPtr<ipc::SharedMemory>();
|
||||
base::SharedMemory shmRW, shmRO;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shmRW->CreateFreezable(1));
|
||||
ASSERT_TRUE(shmRW->Map(1));
|
||||
auto* memRW = reinterpret_cast<char*>(shmRW->Memory());
|
||||
ASSERT_TRUE(shmRW.CreateFreezeable(1));
|
||||
ASSERT_TRUE(shmRW.Map(1));
|
||||
auto memRW = reinterpret_cast<char*>(shmRW.memory());
|
||||
ASSERT_TRUE(memRW);
|
||||
*memRW = 'A';
|
||||
|
||||
// Create read-only copy
|
||||
ASSERT_TRUE(shmRW->ReadOnlyCopy(shmRO));
|
||||
ASSERT_TRUE(shmRO->IsValid());
|
||||
ASSERT_TRUE(shmRW.ReadOnlyCopy(&shmRO));
|
||||
ASSERT_TRUE(shmRO.IsValid());
|
||||
|
||||
// Re-create as writeable
|
||||
auto handle = shmRO->TakeHandleAndUnmap();
|
||||
ASSERT_TRUE(shmRO->IsHandleValid(handle));
|
||||
ASSERT_FALSE(shmRO->IsValid());
|
||||
ASSERT_TRUE(shmRO->SetHandle(std::move(handle),
|
||||
ipc::SharedMemory::OpenRights::RightsReadWrite));
|
||||
ASSERT_TRUE(shmRO->IsValid());
|
||||
auto handle = shmRO.TakeHandle();
|
||||
ASSERT_TRUE(shmRO.IsHandleValid(handle));
|
||||
ASSERT_FALSE(shmRO.IsValid());
|
||||
ASSERT_TRUE(shmRO.SetHandle(std::move(handle), /* read-only */ false));
|
||||
ASSERT_TRUE(shmRO.IsValid());
|
||||
|
||||
// This should fail
|
||||
EXPECT_FALSE(shmRO->Map(1));
|
||||
EXPECT_FALSE(shmRO.Map(1));
|
||||
}
|
||||
|
||||
// See FreezeAndReprotect
|
||||
TEST(IPCSharedMemory, ROCopyAndReprotect)
|
||||
{
|
||||
auto shmRW = MakeRefPtr<ipc::SharedMemory>();
|
||||
auto shmRO = MakeRefPtr<ipc::SharedMemory>();
|
||||
base::SharedMemory shmRW, shmRO;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shmRW->CreateFreezable(1));
|
||||
ASSERT_TRUE(shmRW->Map(1));
|
||||
auto* memRW = reinterpret_cast<char*>(shmRW->Memory());
|
||||
ASSERT_TRUE(shmRW.CreateFreezeable(1));
|
||||
ASSERT_TRUE(shmRW.Map(1));
|
||||
auto memRW = reinterpret_cast<char*>(shmRW.memory());
|
||||
ASSERT_TRUE(memRW);
|
||||
*memRW = 'A';
|
||||
|
||||
// Create read-only copy
|
||||
ASSERT_TRUE(shmRW->ReadOnlyCopy(shmRO));
|
||||
ASSERT_TRUE(shmRO->IsValid());
|
||||
ASSERT_TRUE(shmRW.ReadOnlyCopy(&shmRO));
|
||||
ASSERT_TRUE(shmRO.IsValid());
|
||||
|
||||
// Re-map
|
||||
ASSERT_TRUE(shmRO->Map(1));
|
||||
auto* memRO = reinterpret_cast<char*>(shmRO->Memory());
|
||||
ASSERT_TRUE(shmRO.Map(1));
|
||||
auto memRO = reinterpret_cast<char*>(shmRO.memory());
|
||||
ASSERT_EQ(*memRO, 'A');
|
||||
|
||||
// Try to alter protection; should fail
|
||||
@@ -278,6 +267,20 @@ TEST(IPCSharedMemory, ROCopyAndReprotect)
|
||||
memRO, 1, ipc::SharedMemory::RightsReadWrite));
|
||||
}
|
||||
|
||||
TEST(IPCSharedMemory, IsZero)
|
||||
{
|
||||
base::SharedMemory shm;
|
||||
|
||||
static constexpr size_t kSize = 65536;
|
||||
ASSERT_TRUE(shm.Create(kSize));
|
||||
ASSERT_TRUE(shm.Map(kSize));
|
||||
|
||||
auto* mem = reinterpret_cast<char*>(shm.memory());
|
||||
for (size_t i = 0; i < kSize; ++i) {
|
||||
ASSERT_EQ(mem[i], 0) << "offset " << i;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef FUZZING
|
||||
TEST(IPCSharedMemory, BasicIsZero)
|
||||
{
|
||||
@@ -311,10 +314,9 @@ TEST(IPCSharedMemory, IsMemfd)
|
||||
ASSERT_EQ(sscanf(uts.release, "%d.%d", &major, &minor), 2);
|
||||
bool expectMemfd = major > kMajor || (major == kMajor && minor >= kMinor);
|
||||
|
||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
||||
|
||||
ASSERT_TRUE(shm->Create(1));
|
||||
UniqueFileHandle fd = shm->TakeHandleAndUnmap();
|
||||
base::SharedMemory shm;
|
||||
ASSERT_TRUE(shm.Create(1));
|
||||
UniqueFileHandle fd = shm.TakeHandle();
|
||||
ASSERT_TRUE(fd);
|
||||
|
||||
struct statfs fs;
|
||||
|
||||
@@ -92,8 +92,50 @@ Result<Ok, nsresult> AutoMemMap::initInternal(PRFileMapProtect prot,
|
||||
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);
|
||||
@@ -103,6 +145,12 @@ void AutoMemMap::reset() {
|
||||
Unused << NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS);
|
||||
fileMap = nullptr;
|
||||
}
|
||||
#ifdef XP_WIN
|
||||
if (handle_) {
|
||||
CloseHandle(handle_);
|
||||
handle_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
fd = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,13 @@ class AutoMemMap {
|
||||
PRFileMapProtect prot = PR_PROT_READONLY,
|
||||
size_t maybeSize = 0);
|
||||
|
||||
// Initializes the mapped memory with a shared memory handle. On
|
||||
// Unix-like systems, this is identical to the above init() method. On
|
||||
// Windows, the FileDescriptor must be a handle for a file mapping,
|
||||
// rather than a file descriptor.
|
||||
Result<Ok, nsresult> initWithHandle(const FileDescriptor& file, size_t size,
|
||||
PRFileMapProtect prot = PR_PROT_READONLY);
|
||||
|
||||
void reset();
|
||||
|
||||
bool initialized() const { return addr; }
|
||||
@@ -71,6 +78,13 @@ class AutoMemMap {
|
||||
AutoFDClose fd;
|
||||
PRFileMap* fileMap = nullptr;
|
||||
|
||||
#ifdef XP_WIN
|
||||
// We can't include windows.h in this header, since it gets included
|
||||
// by some binding headers (which are explicitly incompatible with
|
||||
// windows.h). So we can't use the HANDLE type here.
|
||||
void* handle_ = nullptr;
|
||||
#endif
|
||||
|
||||
uint32_t size_ = 0;
|
||||
void* addr = nullptr;
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ void xpc::SelfHostedShmem::InitFromParent(ContentType aXdr) {
|
||||
MOZ_ASSERT(!mLen, "Shouldn't call this more than once");
|
||||
|
||||
size_t len = aXdr.Length();
|
||||
auto shm = mozilla::MakeRefPtr<mozilla::ipc::SharedMemory>();
|
||||
if (NS_WARN_IF(!shm->CreateFreezable(len))) {
|
||||
auto shm = mozilla::MakeUnique<base::SharedMemory>();
|
||||
if (NS_WARN_IF(!shm->CreateFreezeable(len))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -52,29 +52,27 @@ void xpc::SelfHostedShmem::InitFromParent(ContentType aXdr) {
|
||||
return;
|
||||
}
|
||||
|
||||
void* address = shm->Memory();
|
||||
void* address = shm->memory();
|
||||
memcpy(address, aXdr.Elements(), aXdr.LengthBytes());
|
||||
|
||||
RefPtr<mozilla::ipc::SharedMemory> roCopy =
|
||||
mozilla::MakeRefPtr<mozilla::ipc::SharedMemory>();
|
||||
if (NS_WARN_IF(!shm->ReadOnlyCopy(&*roCopy))) {
|
||||
base::SharedMemory roCopy;
|
||||
if (NS_WARN_IF(!shm->ReadOnlyCopy(&roCopy))) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMem = std::move(shm);
|
||||
mHandle = roCopy->TakeHandleAndUnmap();
|
||||
mHandle = roCopy.TakeHandle();
|
||||
mLen = len;
|
||||
}
|
||||
|
||||
bool xpc::SelfHostedShmem::InitFromChild(
|
||||
mozilla::ipc::SharedMemoryHandle aHandle, size_t aLen) {
|
||||
bool xpc::SelfHostedShmem::InitFromChild(::base::SharedMemoryHandle aHandle,
|
||||
size_t aLen) {
|
||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mLen, "Shouldn't call this more than once");
|
||||
|
||||
auto shm = mozilla::MakeRefPtr<mozilla::ipc::SharedMemory>();
|
||||
if (NS_WARN_IF(!shm->SetHandle(std::move(aHandle),
|
||||
mozilla::ipc::SharedMemory::RightsReadOnly))) {
|
||||
auto shm = mozilla::MakeUnique<base::SharedMemory>();
|
||||
if (NS_WARN_IF(!shm->SetHandle(std::move(aHandle), /* read_only */ true))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -94,10 +92,10 @@ xpc::SelfHostedShmem::ContentType xpc::SelfHostedShmem::Content() const {
|
||||
MOZ_ASSERT(mLen == 0);
|
||||
return ContentType();
|
||||
}
|
||||
return ContentType(reinterpret_cast<uint8_t*>(mMem->Memory()), mLen);
|
||||
return ContentType(reinterpret_cast<uint8_t*>(mMem->memory()), mLen);
|
||||
}
|
||||
|
||||
const mozilla::ipc::SharedMemoryHandle& xpc::SelfHostedShmem::Handle() const {
|
||||
const mozilla::UniqueFileHandle& xpc::SelfHostedShmem::Handle() const {
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
#ifndef xpcselfhostedshmem_h___
|
||||
#define xpcselfhostedshmem_h___
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Span.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIThread.h"
|
||||
@@ -48,14 +47,14 @@ class SelfHostedShmem final : public nsIMemoryReporter {
|
||||
//
|
||||
// This function is not thread-safe and should be call at most once and from
|
||||
// the main thread.
|
||||
[[nodiscard]] bool InitFromChild(mozilla::ipc::SharedMemoryHandle aHandle,
|
||||
[[nodiscard]] bool InitFromChild(base::SharedMemoryHandle aHandle,
|
||||
size_t aLen);
|
||||
|
||||
// Return a span over the read-only XDR content of the self-hosted stencil.
|
||||
ContentType Content() const;
|
||||
|
||||
// Return the file handle which is under which the content is mapped.
|
||||
const mozilla::ipc::SharedMemoryHandle& Handle() const;
|
||||
const mozilla::UniqueFileHandle& Handle() const;
|
||||
|
||||
// Register this class to the memory reporter service.
|
||||
void InitMemoryReporter();
|
||||
@@ -76,10 +75,10 @@ class SelfHostedShmem final : public nsIMemoryReporter {
|
||||
|
||||
// read-only file Handle used to transfer from the parent process to content
|
||||
// processes.
|
||||
mozilla::ipc::SharedMemoryHandle mHandle;
|
||||
mozilla::UniqueFileHandle mHandle;
|
||||
|
||||
// Shared memory used by JS runtime initialization.
|
||||
RefPtr<mozilla::ipc::SharedMemory> mMem;
|
||||
mozilla::UniquePtr<base::SharedMemory> mMem;
|
||||
|
||||
// Length of the content within the shared memory.
|
||||
size_t mLen = 0;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/NeverDestroyed.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_layout.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
@@ -105,11 +104,6 @@ namespace mozilla {
|
||||
using namespace mozilla;
|
||||
using namespace css;
|
||||
|
||||
mozilla::ipc::SharedMemoryHandle& sSharedMemoryHandle() {
|
||||
static NeverDestroyed<mozilla::ipc::SharedMemoryHandle> handle;
|
||||
return *handle;
|
||||
}
|
||||
|
||||
#define PREF_LEGACY_STYLESHEET_CUSTOMIZATION \
|
||||
"toolkit.legacyUserProfileCustomizations.stylesheets"
|
||||
|
||||
@@ -179,7 +173,7 @@ GlobalStyleSheetCache::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
if (XRE_IsParentProcess()) {
|
||||
MOZ_COLLECT_REPORT(
|
||||
"explicit/layout/style-sheet-cache/shared", KIND_NONHEAP, UNITS_BYTES,
|
||||
sSharedMemory.IsEmpty() ? 0 : sUsedSharedMemory,
|
||||
sSharedMemory ? sUsedSharedMemory : 0,
|
||||
"Memory used for built-in style sheets that are shared to "
|
||||
"child processes.");
|
||||
}
|
||||
@@ -242,10 +236,10 @@ GlobalStyleSheetCache::GlobalStyleSheetCache() {
|
||||
if (XRE_IsParentProcess()) {
|
||||
// Load the style sheets and store them in a new shared memory buffer.
|
||||
InitSharedSheetsInParent();
|
||||
} else if (!sSharedMemory.IsEmpty()) {
|
||||
// Use the shared memory that was given to us by a SetSharedMemory call
|
||||
// under ContentChild::InitXPCOM.
|
||||
MOZ_ASSERT(sSharedMemory.data(),
|
||||
} else if (sSharedMemory) {
|
||||
// Use the shared memory handle that was given to us by a SetSharedMemory
|
||||
// call under ContentChild::InitXPCOM.
|
||||
MOZ_ASSERT(sSharedMemory->memory(),
|
||||
"GlobalStyleSheetCache::SetSharedMemory should have mapped "
|
||||
"the shared memory");
|
||||
}
|
||||
@@ -264,8 +258,8 @@ GlobalStyleSheetCache::GlobalStyleSheetCache() {
|
||||
// In the parent process, this means we'll just leave our eagerly loaded
|
||||
// non-shared sheets in the mFooSheet fields. In a content process, we'll
|
||||
// lazily load our own copies of the sheets later.
|
||||
if (!sSharedMemory.IsEmpty()) {
|
||||
if (auto* header = reinterpret_cast<Header*>(sSharedMemory.data())) {
|
||||
if (sSharedMemory) {
|
||||
if (auto* header = static_cast<Header*>(sSharedMemory->memory())) {
|
||||
MOZ_RELEASE_ASSERT(header->mMagic == Header::kMagic);
|
||||
|
||||
#define STYLE_SHEET(identifier_, url_, shared_) \
|
||||
@@ -305,10 +299,10 @@ void GlobalStyleSheetCache::LoadSheetFromSharedMemory(
|
||||
|
||||
void GlobalStyleSheetCache::InitSharedSheetsInParent() {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_RELEASE_ASSERT(sSharedMemory.IsEmpty());
|
||||
MOZ_RELEASE_ASSERT(!sSharedMemory);
|
||||
|
||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
||||
if (NS_WARN_IF(!shm->CreateFreezable(kSharedMemorySize))) {
|
||||
auto shm = MakeUnique<base::SharedMemory>();
|
||||
if (NS_WARN_IF(!shm->CreateFreezeable(kSharedMemorySize))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -340,7 +334,7 @@ void GlobalStyleSheetCache::InitSharedSheetsInParent() {
|
||||
#endif
|
||||
|
||||
void* address = nullptr;
|
||||
if (void* p = ipc::SharedMemory::FindFreeAddressSpace(2 * kOffset)) {
|
||||
if (void* p = base::SharedMemory::FindFreeAddressSpace(2 * kOffset)) {
|
||||
address = reinterpret_cast<void*>(uintptr_t(p) + kOffset);
|
||||
}
|
||||
|
||||
@@ -352,7 +346,7 @@ void GlobalStyleSheetCache::InitSharedSheetsInParent() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
address = shm->Memory();
|
||||
address = shm->memory();
|
||||
|
||||
auto* header = static_cast<Header*>(address);
|
||||
header->mMagic = Header::kMagic;
|
||||
@@ -411,8 +405,7 @@ void GlobalStyleSheetCache::InitSharedSheetsInParent() {
|
||||
(Servo_SharedMemoryBuilder_GetLength(builder.get()) + pageSize - 1) &
|
||||
~(pageSize - 1);
|
||||
|
||||
sSharedMemory = shm->TakeMapping();
|
||||
sSharedMemoryHandle() = shm->TakeHandle();
|
||||
sSharedMemory = shm.release();
|
||||
}
|
||||
|
||||
GlobalStyleSheetCache::~GlobalStyleSheetCache() {
|
||||
@@ -535,26 +528,25 @@ RefPtr<StyleSheet> GlobalStyleSheetCache::LoadSheet(
|
||||
}
|
||||
|
||||
/* static */ void GlobalStyleSheetCache::SetSharedMemory(
|
||||
ipc::SharedMemory::Handle aHandle, uintptr_t aAddress) {
|
||||
base::SharedMemoryHandle aHandle, uintptr_t aAddress) {
|
||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||
MOZ_ASSERT(!gStyleCache, "Too late, GlobalStyleSheetCache already created!");
|
||||
MOZ_ASSERT(sSharedMemory.IsEmpty(), "Shouldn't call this more than once");
|
||||
MOZ_ASSERT(!sSharedMemory, "Shouldn't call this more than once");
|
||||
|
||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
||||
if (!shm->SetHandle(std::move(aHandle), ipc::SharedMemory::RightsReadOnly)) {
|
||||
auto shm = MakeUnique<base::SharedMemory>();
|
||||
if (!shm->SetHandle(std::move(aHandle), /* read_only */ true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shm->Map(kSharedMemorySize, reinterpret_cast<void*>(aAddress))) {
|
||||
sSharedMemory = shm->TakeMapping();
|
||||
sSharedMemoryHandle() = shm->TakeHandle();
|
||||
sSharedMemory = shm.release();
|
||||
}
|
||||
}
|
||||
|
||||
ipc::SharedMemoryHandle GlobalStyleSheetCache::CloneHandle() {
|
||||
base::SharedMemoryHandle GlobalStyleSheetCache::CloneHandle() {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
if (ipc::SharedMemory::IsHandleValid(sSharedMemoryHandle())) {
|
||||
return ipc::SharedMemory::CloneHandle(sSharedMemoryHandle());
|
||||
if (sSharedMemory) {
|
||||
return sSharedMemory->CloneHandle();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -563,7 +555,7 @@ StaticRefPtr<GlobalStyleSheetCache> GlobalStyleSheetCache::gStyleCache;
|
||||
StaticRefPtr<css::Loader> GlobalStyleSheetCache::gCSSLoader;
|
||||
StaticRefPtr<nsIURI> GlobalStyleSheetCache::gUserContentSheetURL;
|
||||
|
||||
Span<uint8_t> GlobalStyleSheetCache::sSharedMemory;
|
||||
StaticAutoPtr<base::SharedMemory> GlobalStyleSheetCache::sSharedMemory;
|
||||
size_t GlobalStyleSheetCache::sUsedSharedMemory;
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "base/shared_memory.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/PreferenceSheet.h"
|
||||
@@ -16,7 +17,6 @@
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/UserAgentStyleSheetID.h"
|
||||
#include "mozilla/css/Loader.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
class nsIFile;
|
||||
class nsIURI;
|
||||
@@ -60,18 +60,18 @@ class GlobalStyleSheetCache final : public nsIObserver,
|
||||
// Called early on in a content process' life from
|
||||
// ContentChild::InitSharedUASheets, before the GlobalStyleSheetCache
|
||||
// singleton has been created.
|
||||
static void SetSharedMemory(mozilla::ipc::SharedMemory::Handle aHandle,
|
||||
static void SetSharedMemory(base::SharedMemoryHandle aHandle,
|
||||
uintptr_t aAddress);
|
||||
|
||||
// Obtain a shared memory handle for the shared UA sheets to pass into a
|
||||
// content process. Called by ContentParent::InitInternal shortly after
|
||||
// a content process has been created.
|
||||
mozilla::ipc::SharedMemoryHandle CloneHandle();
|
||||
base::SharedMemoryHandle CloneHandle();
|
||||
|
||||
// Returns the address of the shared memory segment that holds the shared UA
|
||||
// sheets.
|
||||
uintptr_t GetSharedMemoryAddress() {
|
||||
return sSharedMemory.IsEmpty() ? 0 : uintptr_t(sSharedMemory.data());
|
||||
return sSharedMemory ? uintptr_t(sSharedMemory->memory()) : 0;
|
||||
}
|
||||
|
||||
// Size of the shared memory buffer we'll create to store the shared UA
|
||||
@@ -120,7 +120,7 @@ class GlobalStyleSheetCache final : public nsIObserver,
|
||||
RefPtr<StyleSheet> mUserContentSheet;
|
||||
|
||||
// Shared memory segment storing shared style sheets.
|
||||
static Span<uint8_t> sSharedMemory;
|
||||
static StaticAutoPtr<base::SharedMemory> sSharedMemory;
|
||||
|
||||
// How much of the shared memory buffer we ended up using. Used for memory
|
||||
// reporting in the parent process.
|
||||
|
||||
@@ -3833,7 +3833,7 @@ void Preferences::DeserializePreferences(char* aStr, size_t aPrefsLen) {
|
||||
}
|
||||
|
||||
/* static */
|
||||
mozilla::ipc::SharedMemoryHandle Preferences::EnsureSnapshot(size_t* aSize) {
|
||||
FileDescriptor Preferences::EnsureSnapshot(size_t* aSize) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
@@ -3883,12 +3883,11 @@ mozilla::ipc::SharedMemoryHandle Preferences::EnsureSnapshot(size_t* aSize) {
|
||||
}
|
||||
|
||||
*aSize = gSharedMap->MapSize();
|
||||
return gSharedMap->CloneHandle();
|
||||
return gSharedMap->CloneFileDescriptor();
|
||||
}
|
||||
|
||||
/* static */
|
||||
void Preferences::InitSnapshot(const mozilla::ipc::SharedMemoryHandle& aHandle,
|
||||
size_t aSize) {
|
||||
void Preferences::InitSnapshot(const FileDescriptor& aHandle, size_t aSize) {
|
||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||
MOZ_ASSERT(!gSharedMap);
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
@@ -410,11 +409,8 @@ class Preferences final : public nsIPrefService,
|
||||
bool aIsDestinationWebContentProcess);
|
||||
static void DeserializePreferences(char* aStr, size_t aPrefsLen);
|
||||
|
||||
#ifndef RUST_BINDGEN
|
||||
static mozilla::ipc::SharedMemoryHandle EnsureSnapshot(size_t* aSize);
|
||||
static void InitSnapshot(const mozilla::ipc::SharedMemoryHandle&,
|
||||
size_t aSize);
|
||||
#endif
|
||||
static mozilla::ipc::FileDescriptor EnsureSnapshot(size_t* aSize);
|
||||
static void InitSnapshot(const mozilla::ipc::FileDescriptor&, size_t aSize);
|
||||
|
||||
// When a single pref is changed in the parent process, these methods are
|
||||
// used to pass the update to content processes.
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "mozilla/Try.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
|
||||
using namespace mozilla::loader;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace ipc;
|
||||
@@ -22,38 +24,24 @@ static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) {
|
||||
return mod ? aAlign - mod : 0;
|
||||
}
|
||||
|
||||
SharedPrefMap::SharedPrefMap(const SharedMemoryHandle& aMapHandle,
|
||||
size_t aMapSize) {
|
||||
auto map = MakeRefPtr<SharedMemory>();
|
||||
{
|
||||
auto result = map->SetHandle(SharedMemory::CloneHandle(aMapHandle),
|
||||
SharedMemory::OpenRights::RightsReadOnly);
|
||||
MOZ_RELEASE_ASSERT(result);
|
||||
}
|
||||
{
|
||||
auto result = map->Map(aMapSize);
|
||||
MOZ_RELEASE_ASSERT(result);
|
||||
}
|
||||
|
||||
SharedPrefMap::SharedPrefMap(const FileDescriptor& aMapFile, size_t aMapSize) {
|
||||
auto result = mMap.initWithHandle(aMapFile, aMapSize);
|
||||
MOZ_RELEASE_ASSERT(result.isOk());
|
||||
// We return literal nsCStrings pointing to the mapped data for preference
|
||||
// names and string values, which means that we may still have references to
|
||||
// the mapped data even after this instance is destroyed. That means that we
|
||||
// need to keep the mapping alive until process shutdown, in order to be safe.
|
||||
mMappedMemory = map->TakeMapping();
|
||||
mHandle = map->TakeHandle();
|
||||
mMap.setPersistent();
|
||||
}
|
||||
|
||||
SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder&& aBuilder) {
|
||||
RefPtr<SharedMemory> map;
|
||||
auto result = aBuilder.Finalize(map);
|
||||
MOZ_RELEASE_ASSERT(result.isOk() && map);
|
||||
|
||||
mMappedMemory = map->TakeMapping();
|
||||
mHandle = map->TakeHandle();
|
||||
auto result = aBuilder.Finalize(mMap);
|
||||
MOZ_RELEASE_ASSERT(result.isOk());
|
||||
mMap.setPersistent();
|
||||
}
|
||||
|
||||
mozilla::ipc::SharedMemoryHandle SharedPrefMap::CloneHandle() const {
|
||||
return SharedMemory::CloneHandle(mHandle);
|
||||
mozilla::ipc::FileDescriptor SharedPrefMap::CloneFileDescriptor() const {
|
||||
return mMap.cloneHandle();
|
||||
}
|
||||
|
||||
bool SharedPrefMap::Has(const char* aKey) const {
|
||||
@@ -148,8 +136,7 @@ void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
|
||||
});
|
||||
}
|
||||
|
||||
Result<Ok, nsresult> SharedPrefMapBuilder::Finalize(
|
||||
RefPtr<SharedMemory>& aMap) {
|
||||
Result<Ok, nsresult> SharedPrefMapBuilder::Finalize(loader::AutoMemMap& aMap) {
|
||||
using Header = SharedPrefMap::Header;
|
||||
|
||||
// Create an array of entry pointers for the entry array, and sort it by
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
#ifndef dom_ipc_SharedPrefMap_h
|
||||
#define dom_ipc_SharedPrefMap_h
|
||||
|
||||
#include "mozilla/AutoMemMap.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/dom/ipc/StringTable.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "nsTHashMap.h"
|
||||
|
||||
namespace mozilla {
|
||||
@@ -52,6 +52,8 @@ class SharedPrefMapBuilder;
|
||||
// instance has been initialized, the memory that it allocates can never be
|
||||
// freed before process shutdown. Do not use it for short-lived mappings.
|
||||
class SharedPrefMap {
|
||||
using FileDescriptor = mozilla::ipc::FileDescriptor;
|
||||
|
||||
friend class SharedPrefMapBuilder;
|
||||
|
||||
// Describes a block of memory within the shared memory region.
|
||||
@@ -419,7 +421,7 @@ class SharedPrefMap {
|
||||
|
||||
// Note: These constructors are infallible, because the preference database is
|
||||
// critical to platform functionality, and we cannot operate without it.
|
||||
SharedPrefMap(const mozilla::ipc::SharedMemoryHandle&, size_t);
|
||||
SharedPrefMap(const FileDescriptor&, size_t);
|
||||
explicit SharedPrefMap(SharedPrefMapBuilder&&);
|
||||
|
||||
// Searches for the given preference in the map, and returns true if it
|
||||
@@ -498,15 +500,15 @@ class SharedPrefMap {
|
||||
// makes its purpose slightly clearer.
|
||||
const SharedPrefMap& Iter() const { return *this; }
|
||||
|
||||
// Returns a copy of the read-only shared memory handle which backs the shared
|
||||
// memory region for this map. The handle may be passed between processes, and
|
||||
// used to construct new instances of SharedPrefMap with the same data as this
|
||||
// instance.
|
||||
mozilla::ipc::SharedMemoryHandle CloneHandle() const;
|
||||
// Returns a copy of the read-only file descriptor which backs the shared
|
||||
// memory region for this map. The file descriptor may be passed between
|
||||
// processes, and used to construct new instances of SharedPrefMap with
|
||||
// the same data as this instance.
|
||||
FileDescriptor CloneFileDescriptor() const;
|
||||
|
||||
// Returns the size of the mapped memory region. This size must be passed to
|
||||
// the constructor when mapping the shared region in another process.
|
||||
size_t MapSize() const { return mMappedMemory.size(); }
|
||||
size_t MapSize() const { return mMap.size(); }
|
||||
|
||||
protected:
|
||||
~SharedPrefMap() = default;
|
||||
@@ -516,9 +518,7 @@ class SharedPrefMap {
|
||||
using StringTable = mozilla::dom::ipc::StringTable<T>;
|
||||
|
||||
// Type-safe getters for values in the shared memory region:
|
||||
const Header& GetHeader() const {
|
||||
return *reinterpret_cast<const Header*>(mMappedMemory.data());
|
||||
}
|
||||
const Header& GetHeader() const { return mMap.get<Header>()[0]; }
|
||||
|
||||
RangedPtr<const Entry> Entries() const {
|
||||
return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()};
|
||||
@@ -528,7 +528,7 @@ class SharedPrefMap {
|
||||
|
||||
template <typename T>
|
||||
RangedPtr<const T> GetBlock(const DataBlock& aBlock) const {
|
||||
return RangedPtr<uint8_t>(&mMappedMemory.data()[aBlock.mOffset],
|
||||
return RangedPtr<uint8_t>(&mMap.get<uint8_t>()[aBlock.mOffset],
|
||||
aBlock.mSize)
|
||||
.ReinterpretCast<const T>();
|
||||
}
|
||||
@@ -549,19 +549,15 @@ class SharedPrefMap {
|
||||
|
||||
StringTable<nsCString> KeyTable() const {
|
||||
auto& block = GetHeader().mKeyStrings;
|
||||
return {{&mMappedMemory.data()[block.mOffset], block.mSize}};
|
||||
return {{&mMap.get<uint8_t>()[block.mOffset], block.mSize}};
|
||||
}
|
||||
|
||||
StringTable<nsCString> ValueTable() const {
|
||||
auto& block = GetHeader().mValueStrings;
|
||||
return {{&mMappedMemory.data()[block.mOffset], block.mSize}};
|
||||
return {{&mMap.get<uint8_t>()[block.mOffset], block.mSize}};
|
||||
}
|
||||
|
||||
mozilla::ipc::SharedMemoryHandle mHandle;
|
||||
// This is a leaked shared memory mapping (see the constructor definition for
|
||||
// an explanation). It replaces AutoMemMap::setPersistent behavior as part of
|
||||
// bug 1454816.
|
||||
Span<uint8_t> mMappedMemory;
|
||||
loader::AutoMemMap mMap;
|
||||
};
|
||||
|
||||
// A helper class which builds the contiguous look-up table used by
|
||||
@@ -591,13 +587,13 @@ class MOZ_RAII SharedPrefMapBuilder {
|
||||
const nsCString& aDefaultValue, const nsCString& aUserValue);
|
||||
|
||||
// Finalizes the binary representation of the map, writes it to a shared
|
||||
// memory region, and then initializes the given SharedMemory with a reference
|
||||
// memory region, and then initializes the given AutoMemMap with a reference
|
||||
// to the read-only copy of it.
|
||||
//
|
||||
// This should generally not be used directly by callers. The
|
||||
// SharedPrefMapBuilder instance should instead be passed to the SharedPrefMap
|
||||
// constructor as a move reference.
|
||||
Result<Ok, nsresult> Finalize(RefPtr<mozilla::ipc::SharedMemory>& aMap);
|
||||
Result<Ok, nsresult> Finalize(loader::AutoMemMap& aMap);
|
||||
|
||||
private:
|
||||
using StringTableEntry = mozilla::dom::ipc::StringTableEntry;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "SocketProcessImpl.h"
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/shared_memory.h"
|
||||
#include "base/string_util.h"
|
||||
#include "mozilla/BackgroundHangMonitor.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "SandboxInfo.h"
|
||||
#include "SandboxLogging.h"
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
#include "mozilla/Array.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Omnijar.h"
|
||||
@@ -18,7 +19,6 @@
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsString.h"
|
||||
@@ -323,7 +323,7 @@ static void AddLdLibraryEnvPaths(SandboxBroker::Policy* aPolicy) {
|
||||
|
||||
static void AddSharedMemoryPaths(SandboxBroker::Policy* aPolicy, pid_t aPid) {
|
||||
std::string shmPath("/dev/shm");
|
||||
if (ipc::SharedMemory::AppendPosixShmPrefix(&shmPath, aPid)) {
|
||||
if (base::SharedMemory::AppendPosixShmPrefix(&shmPath, aPid)) {
|
||||
aPolicy->AddPrefix(rdwrcr, shmPath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "mozilla/CmdLineAndEnvUtils.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
@@ -188,14 +187,14 @@ static CommandLineArg<const char*> sProfile{"-profile", "profile"};
|
||||
|
||||
static CommandLineArg<UniqueFileHandle> sIPCHandle{"-ipcHandle", "ipchandle"};
|
||||
|
||||
static CommandLineArg<mozilla::ipc::SharedMemoryHandle> sJsInitHandle{
|
||||
"-jsInitHandle", "jsinithandle"};
|
||||
static CommandLineArg<UniqueFileHandle> sJsInitHandle{"-jsInitHandle",
|
||||
"jsinithandle"};
|
||||
static CommandLineArg<uint64_t> sJsInitLen{"-jsInitLen", "jsinitlen"};
|
||||
static CommandLineArg<mozilla::ipc::SharedMemoryHandle> sPrefsHandle{
|
||||
"-prefsHandle", "prefshandle"};
|
||||
static CommandLineArg<UniqueFileHandle> sPrefsHandle{"-prefsHandle",
|
||||
"prefshandle"};
|
||||
static CommandLineArg<uint64_t> sPrefsLen{"-prefsLen", "prefslen"};
|
||||
static CommandLineArg<mozilla::ipc::SharedMemoryHandle> sPrefMapHandle{
|
||||
"-prefMapHandle", "prefmaphandle"};
|
||||
static CommandLineArg<UniqueFileHandle> sPrefMapHandle{"-prefMapHandle",
|
||||
"prefmaphandle"};
|
||||
static CommandLineArg<uint64_t> sPrefMapSize{"-prefMapSize", "prefmapsize"};
|
||||
|
||||
static CommandLineArg<uint64_t> sSandboxingKind{"-sandboxingKind",
|
||||
|
||||
@@ -52,7 +52,7 @@ RefPtr<WaylandShmPool> WaylandShmPool::Create(nsWaylandDisplay* aWaylandDisplay,
|
||||
|
||||
RefPtr<WaylandShmPool> shmPool = new WaylandShmPool();
|
||||
|
||||
shmPool->mShm = MakeRefPtr<ipc::SharedMemory>();
|
||||
shmPool->mShm = MakeUnique<base::SharedMemory>();
|
||||
if (!shmPool->mShm->Create(aSize)) {
|
||||
NS_WARNING("WaylandShmPool: Unable to allocate shared memory!");
|
||||
return nullptr;
|
||||
@@ -77,7 +77,7 @@ void* WaylandShmPool::GetImageData() {
|
||||
NS_WARNING("WaylandShmPool: Failed to map Shm!");
|
||||
return nullptr;
|
||||
}
|
||||
mImageData = mShm->Memory();
|
||||
mImageData = mShm->memory();
|
||||
return mImageData;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,12 @@
|
||||
#include "DMABufSurface.h"
|
||||
#include "GLContext.h"
|
||||
#include "MozFramebuffer.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWaylandDisplay.h"
|
||||
#include "base/shared_memory.h"
|
||||
|
||||
namespace mozilla::widget {
|
||||
|
||||
@@ -37,7 +36,7 @@ class WaylandShmPool {
|
||||
|
||||
wl_shm_pool* mShmPool = nullptr;
|
||||
void* mImageData = nullptr;
|
||||
RefPtr<ipc::SharedMemory> mShm;
|
||||
UniquePtr<base::SharedMemory> mShm;
|
||||
int mSize = 0;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user