1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/memory/shared_memory.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/rand_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
17 // Returns the length of the memory section starting at the supplied address.
18 size_t GetMemorySectionSize(void* address
) {
19 MEMORY_BASIC_INFORMATION memory_info
;
20 if (!::VirtualQuery(address
, &memory_info
, sizeof(memory_info
)))
22 return memory_info
.RegionSize
- (static_cast<char*>(address
) -
23 static_cast<char*>(memory_info
.AllocationBase
));
30 SharedMemory::SharedMemory()
38 SharedMemory::SharedMemory(const std::wstring
& name
)
47 SharedMemory::SharedMemory(SharedMemoryHandle handle
, bool read_only
)
48 : mapped_file_(handle
),
50 read_only_(read_only
),
55 SharedMemory::SharedMemory(SharedMemoryHandle handle
,
57 ProcessHandle process
)
60 read_only_(read_only
),
63 ::DuplicateHandle(process
, handle
,
64 GetCurrentProcess(), &mapped_file_
,
65 read_only_
? FILE_MAP_READ
: FILE_MAP_READ
|
70 SharedMemory::~SharedMemory() {
76 bool SharedMemory::IsHandleValid(const SharedMemoryHandle
& handle
) {
77 return handle
!= NULL
;
81 SharedMemoryHandle
SharedMemory::NULLHandle() {
86 void SharedMemory::CloseHandle(const SharedMemoryHandle
& handle
) {
87 DCHECK(handle
!= NULL
);
88 ::CloseHandle(handle
);
92 size_t SharedMemory::GetHandleLimit() {
93 // Rounded down from value reported here:
94 // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx
95 return static_cast<size_t>(1 << 23);
99 SharedMemoryHandle
SharedMemory::DuplicateHandle(
100 const SharedMemoryHandle
& handle
) {
101 ProcessHandle process
= GetCurrentProcess();
102 SharedMemoryHandle duped_handle
;
103 BOOL success
= ::DuplicateHandle(process
, handle
, process
, &duped_handle
, 0,
104 FALSE
, DUPLICATE_SAME_ACCESS
);
110 bool SharedMemory::CreateAndMapAnonymous(size_t size
) {
111 return CreateAnonymous(size
) && Map(size
);
114 bool SharedMemory::Create(const SharedMemoryCreateOptions
& options
) {
115 // TODO(bsy,sehr): crbug.com/210609 NaCl forces us to round up 64k here,
116 // wasting 32k per mapping on average.
117 static const size_t kSectionMask
= 65536 - 1;
118 DCHECK(!options
.executable
);
119 DCHECK(!mapped_file_
);
120 if (options
.size
== 0)
123 // Check maximum accounting for overflow.
125 static_cast<size_t>(std::numeric_limits
<int>::max()) - kSectionMask
)
128 size_t rounded_size
= (options
.size
+ kSectionMask
) & ~kSectionMask
;
129 name_
= options
.name_deprecated
?
130 ASCIIToUTF16(*options
.name_deprecated
) : L
"";
131 SECURITY_ATTRIBUTES sa
= { sizeof(sa
), NULL
, FALSE
};
132 SECURITY_DESCRIPTOR sd
;
135 if (options
.share_read_only
&& name_
.empty()) {
136 // Add an empty DACL to enforce anonymous read-only sections.
137 sa
.lpSecurityDescriptor
= &sd
;
138 if (!InitializeAcl(&dacl
, sizeof(dacl
), ACL_REVISION
))
140 if (!InitializeSecurityDescriptor(&sd
, SECURITY_DESCRIPTOR_REVISION
))
142 if (!SetSecurityDescriptorDacl(&sd
, TRUE
, &dacl
, FALSE
))
145 // Windows ignores DACLs on certain unnamed objects (like shared sections).
146 // So, we generate a random name when we need to enforce read-only.
147 uint64_t rand_values
[4];
148 RandBytes(&rand_values
, sizeof(rand_values
));
149 name_
= StringPrintf(L
"CrSharedMem_%016x%016x%016x%016x",
150 rand_values
[0], rand_values
[1],
151 rand_values
[2], rand_values
[3]);
153 mapped_file_
= CreateFileMapping(INVALID_HANDLE_VALUE
, &sa
,
154 PAGE_READWRITE
, 0, static_cast<DWORD
>(rounded_size
),
155 name_
.empty() ? nullptr : name_
.c_str());
159 requested_size_
= options
.size
;
161 // Check if the shared memory pre-exists.
162 if (GetLastError() == ERROR_ALREADY_EXISTS
) {
163 // If the file already existed, set requested_size_ to 0 to show that
164 // we don't know the size.
166 if (!options
.open_existing_deprecated
) {
175 bool SharedMemory::Delete(const std::string
& name
) {
176 // intentionally empty -- there is nothing for us to do on Windows.
180 bool SharedMemory::Open(const std::string
& name
, bool read_only
) {
181 DCHECK(!mapped_file_
);
183 name_
= ASCIIToUTF16(name
);
184 read_only_
= read_only
;
185 mapped_file_
= OpenFileMapping(
186 read_only_
? FILE_MAP_READ
: FILE_MAP_READ
| FILE_MAP_WRITE
,
187 false, name_
.empty() ? NULL
: name_
.c_str());
188 if (mapped_file_
!= NULL
) {
189 // Note: size_ is not set in this case.
195 bool SharedMemory::MapAt(off_t offset
, size_t bytes
) {
196 if (mapped_file_
== NULL
)
199 if (bytes
> static_cast<size_t>(std::numeric_limits
<int>::max()))
205 memory_
= MapViewOfFile(mapped_file_
,
206 read_only_
? FILE_MAP_READ
: FILE_MAP_READ
|
208 static_cast<uint64
>(offset
) >> 32,
209 static_cast<DWORD
>(offset
),
211 if (memory_
!= NULL
) {
212 DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_
) &
213 (SharedMemory::MAP_MINIMUM_ALIGNMENT
- 1));
214 mapped_size_
= GetMemorySectionSize(memory_
);
220 bool SharedMemory::Unmap() {
224 UnmapViewOfFile(memory_
);
229 bool SharedMemory::ShareToProcessCommon(ProcessHandle process
,
230 SharedMemoryHandle
* new_handle
,
232 ShareMode share_mode
) {
234 DWORD access
= FILE_MAP_READ
;
236 HANDLE mapped_file
= mapped_file_
;
238 if (share_mode
== SHARE_CURRENT_MODE
&& !read_only_
)
239 access
|= FILE_MAP_WRITE
;
241 // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file.
242 options
= DUPLICATE_CLOSE_SOURCE
;
247 if (process
== GetCurrentProcess() && close_self
) {
248 *new_handle
= mapped_file
;
252 if (!::DuplicateHandle(GetCurrentProcess(), mapped_file
, process
, &result
,
253 access
, FALSE
, options
)) {
256 *new_handle
= result
;
261 void SharedMemory::Close() {
262 if (mapped_file_
!= NULL
) {
263 CloseHandle(mapped_file_
);
268 SharedMemoryHandle
SharedMemory::handle() const {