1 /* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "SharedMemory.h" 28 29 #include "ArgumentDecoder.h" 30 #include "ArgumentEncoder.h" 31 #include <wtf/RefPtr.h> 32 33 namespace WebKit { 34 35 SharedMemory::Handle::Handle() 36 : m_handle(0) 37 , m_size(0) 38 { 39 } 40 41 SharedMemory::Handle::~Handle() 42 { 43 if (!m_handle) 44 return; 45 46 ::CloseHandle(m_handle); 47 } 48 49 bool SharedMemory::Handle::isNull() const 50 { 51 return !m_handle; 52 } 53 54 void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const 55 { 56 encoder->encodeUInt64(m_size); 57 58 // Hand off ownership of our HANDLE to the receiving process. It will close it for us. 59 // FIXME: If the receiving process crashes before it receives the memory, the memory will be 60 // leaked. See <http://webkit.org/b/47502>. 61 encoder->encodeUInt64(reinterpret_cast<uint64_t>(m_handle)); 62 m_handle = 0; 63 64 // Send along our PID so that the receiving process can duplicate the HANDLE for its own use. 65 encoder->encodeUInt32(::GetCurrentProcessId()); 66 } 67 68 static bool getDuplicatedHandle(HANDLE sourceHandle, DWORD sourcePID, HANDLE& duplicatedHandle) 69 { 70 duplicatedHandle = 0; 71 if (!sourceHandle) 72 return true; 73 74 HANDLE sourceProcess = ::OpenProcess(PROCESS_DUP_HANDLE, FALSE, sourcePID); 75 if (!sourceProcess) 76 return false; 77 78 // Copy the handle into our process and close the handle that the sending process created for us. 79 BOOL success = ::DuplicateHandle(sourceProcess, sourceHandle, ::GetCurrentProcess(), &duplicatedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); 80 ASSERT_WITH_MESSAGE(success, "::DuplicateHandle failed with error %lu", ::GetLastError()); 81 82 ::CloseHandle(sourceProcess); 83 84 return success; 85 } 86 87 bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle) 88 { 89 ASSERT_ARG(handle, !handle.m_handle); 90 ASSERT_ARG(handle, !handle.m_size); 91 92 uint64_t size; 93 if (!decoder->decodeUInt64(size)) 94 return false; 95 96 uint64_t sourceHandle; 97 if (!decoder->decodeUInt64(sourceHandle)) 98 return false; 99 100 uint32_t sourcePID; 101 if (!decoder->decodeUInt32(sourcePID)) 102 return false; 103 104 HANDLE duplicatedHandle; 105 if (!getDuplicatedHandle(reinterpret_cast<HANDLE>(sourceHandle), sourcePID, duplicatedHandle)) 106 return false; 107 108 handle.m_handle = duplicatedHandle; 109 handle.m_size = size; 110 return true; 111 } 112 113 PassRefPtr<SharedMemory> SharedMemory::create(size_t size) 114 { 115 HANDLE handle = ::CreateFileMappingW(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size, 0); 116 if (!handle) 117 return 0; 118 119 void* baseAddress = ::MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, size); 120 if (!baseAddress) { 121 ::CloseHandle(handle); 122 return 0; 123 } 124 125 RefPtr<SharedMemory> memory = adoptRef(new SharedMemory); 126 memory->m_size = size; 127 memory->m_data = baseAddress; 128 memory->m_handle = handle; 129 130 return memory.release(); 131 } 132 133 static DWORD accessRights(SharedMemory::Protection protection) 134 { 135 switch (protection) { 136 case SharedMemory::ReadOnly: 137 return FILE_MAP_READ; 138 case SharedMemory::ReadWrite: 139 return FILE_MAP_READ | FILE_MAP_WRITE; 140 } 141 142 ASSERT_NOT_REACHED(); 143 return 0; 144 } 145 146 PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection) 147 { 148 RefPtr<SharedMemory> memory = adopt(handle.m_handle, handle.m_size, protection); 149 if (!memory) 150 return 0; 151 152 // The SharedMemory object now owns the HANDLE. 153 handle.m_handle = 0; 154 155 return memory.release(); 156 } 157 158 PassRefPtr<SharedMemory> SharedMemory::adopt(HANDLE handle, size_t size, Protection protection) 159 { 160 if (!handle) 161 return 0; 162 163 DWORD desiredAccess = accessRights(protection); 164 165 void* baseAddress = ::MapViewOfFile(handle, desiredAccess, 0, 0, size); 166 ASSERT_WITH_MESSAGE(baseAddress, "::MapViewOfFile failed with error %lu", ::GetLastError()); 167 if (!baseAddress) 168 return 0; 169 170 RefPtr<SharedMemory> memory = adoptRef(new SharedMemory); 171 memory->m_size = size; 172 memory->m_data = baseAddress; 173 memory->m_handle = handle; 174 175 return memory.release(); 176 } 177 178 SharedMemory::~SharedMemory() 179 { 180 ASSERT(m_data); 181 ASSERT(m_handle); 182 183 ::UnmapViewOfFile(m_data); 184 ::CloseHandle(m_handle); 185 } 186 187 bool SharedMemory::createHandle(Handle& handle, Protection protection) 188 { 189 ASSERT_ARG(handle, !handle.m_handle); 190 ASSERT_ARG(handle, !handle.m_size); 191 192 HANDLE processHandle = ::GetCurrentProcess(); 193 194 HANDLE duplicatedHandle; 195 if (!::DuplicateHandle(processHandle, m_handle, processHandle, &duplicatedHandle, accessRights(protection), FALSE, 0)) 196 return false; 197 198 handle.m_handle = duplicatedHandle; 199 handle.m_size = m_size; 200 return true; 201 } 202 203 unsigned SharedMemory::systemPageSize() 204 { 205 static unsigned pageSize = 0; 206 207 if (!pageSize) { 208 SYSTEM_INFO systemInfo; 209 ::GetSystemInfo(&systemInfo); 210 pageSize = systemInfo.dwPageSize; 211 } 212 213 return pageSize; 214 } 215 216 } // namespace WebKit 217