File: | bridges/source/cpp_uno/shared/vtablefactory.cxx |
Location: | line 377, column 31 |
Description: | Access to field 'nBaseTypes' results in a dereference of a null pointer (loaded from variable 'type') |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /************************************************************************* | |||
3 | * | |||
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |||
5 | * | |||
6 | * Copyright 2000, 2010 Oracle and/or its affiliates. | |||
7 | * | |||
8 | * OpenOffice.org - a multi-platform office productivity suite | |||
9 | * | |||
10 | * This file is part of OpenOffice.org. | |||
11 | * | |||
12 | * OpenOffice.org is free software: you can redistribute it and/or modify | |||
13 | * it under the terms of the GNU Lesser General Public License version 3 | |||
14 | * only, as published by the Free Software Foundation. | |||
15 | * | |||
16 | * OpenOffice.org is distributed in the hope that it will be useful, | |||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
19 | * GNU Lesser General Public License version 3 for more details | |||
20 | * (a copy is included in the LICENSE file that accompanied this code). | |||
21 | * | |||
22 | * You should have received a copy of the GNU Lesser General Public License | |||
23 | * version 3 along with OpenOffice.org. If not, see | |||
24 | * <http://www.openoffice.org/license.html> | |||
25 | * for a copy of the LGPLv3 License. | |||
26 | * | |||
27 | ************************************************************************/ | |||
28 | ||||
29 | ||||
30 | #include "bridges/cpp_uno/shared/vtablefactory.hxx" | |||
31 | ||||
32 | #include "guardedarray.hxx" | |||
33 | ||||
34 | #include "bridges/cpp_uno/shared/vtables.hxx" | |||
35 | ||||
36 | #include "osl/thread.h" | |||
37 | #include "osl/security.hxx" | |||
38 | #include "osl/file.hxx" | |||
39 | #include "osl/diagnose.h" | |||
40 | #include "osl/mutex.hxx" | |||
41 | #include "rtl/alloc.h" | |||
42 | #include "rtl/ustring.hxx" | |||
43 | #include "sal/log.hxx" | |||
44 | #include "sal/types.h" | |||
45 | #include "typelib/typedescription.hxx" | |||
46 | ||||
47 | #include <boost/unordered_map.hpp> | |||
48 | #include <new> | |||
49 | #include <vector> | |||
50 | ||||
51 | #if defined SAL_UNX | |||
52 | #include <unistd.h> | |||
53 | #include <string.h> | |||
54 | #include <errno(*__errno_location ()).h> | |||
55 | #include <sys/mman.h> | |||
56 | #elif defined SAL_W32 | |||
57 | #define WIN32_LEAN_AND_MEAN | |||
58 | #ifdef _MSC_VER | |||
59 | #pragma warning(push,1) // disable warnings within system headers | |||
60 | #endif | |||
61 | #include <windows.h> | |||
62 | #ifdef _MSC_VER | |||
63 | #pragma warning(pop) | |||
64 | #endif | |||
65 | #else | |||
66 | #error Unsupported platform | |||
67 | #endif | |||
68 | ||||
69 | #if defined USE_DOUBLE_MMAP | |||
70 | #include <fcntl.h> | |||
71 | #endif | |||
72 | ||||
73 | using bridges::cpp_uno::shared::VtableFactory; | |||
74 | ||||
75 | namespace { | |||
76 | ||||
77 | extern "C" void * SAL_CALL allocExec( | |||
78 | SAL_UNUSED_PARAMETER__attribute__ ((unused)) rtl_arena_type *, sal_Size * size) | |||
79 | { | |||
80 | sal_Size pagesize; | |||
81 | #if defined SAL_UNX | |||
82 | #if defined FREEBSD || defined NETBSD || defined OPENBSD || defined DRAGONFLY | |||
83 | pagesize = getpagesize(); | |||
84 | #else | |||
85 | pagesize = sysconf(_SC_PAGESIZE_SC_PAGESIZE); | |||
86 | #endif | |||
87 | #elif defined SAL_W32 | |||
88 | SYSTEM_INFO info; | |||
89 | GetSystemInfo(&info); | |||
90 | pagesize = info.dwPageSize; | |||
91 | #else | |||
92 | #error Unsupported platform | |||
93 | #endif | |||
94 | sal_Size n = (*size + (pagesize - 1)) & ~(pagesize - 1); | |||
95 | void * p; | |||
96 | #if defined SAL_UNX | |||
97 | p = mmap( | |||
98 | 0, n, PROT_READ0x1 | PROT_WRITE0x2, MAP_PRIVATE0x02 | MAP_ANON0x20, -1, | |||
99 | 0); | |||
100 | if (p == MAP_FAILED((void *) -1)) { | |||
101 | p = 0; | |||
102 | } | |||
103 | else if (mprotect (static_cast<char*>(p), n, PROT_READ0x1 | PROT_WRITE0x2 | PROT_EXEC0x4) == -1) | |||
104 | { | |||
105 | munmap (static_cast<char*>(p), n); | |||
106 | p = 0; | |||
107 | } | |||
108 | #elif defined SAL_W32 | |||
109 | p = VirtualAlloc(0, n, MEM_COMMIT, PAGE_EXECUTE_READWRITE); | |||
110 | #endif | |||
111 | if (p != 0) { | |||
112 | *size = n; | |||
113 | } | |||
114 | return p; | |||
115 | } | |||
116 | ||||
117 | extern "C" void SAL_CALL freeExec( | |||
118 | SAL_UNUSED_PARAMETER__attribute__ ((unused)) rtl_arena_type *, void * address, sal_Size size) | |||
119 | { | |||
120 | #if defined SAL_UNX | |||
121 | munmap(static_cast< char * >(address), size); | |||
122 | #elif defined SAL_W32 | |||
123 | (void) size; // unused | |||
124 | VirtualFree(address, 0, MEM_RELEASE); | |||
125 | #endif | |||
126 | } | |||
127 | ||||
128 | } | |||
129 | ||||
130 | class VtableFactory::GuardedBlocks: public std::vector< Block > { | |||
131 | public: | |||
132 | GuardedBlocks(VtableFactory const & factory): | |||
133 | m_factory(factory), m_guarded(true) {} | |||
134 | ||||
135 | ~GuardedBlocks(); | |||
136 | ||||
137 | void unguard() { m_guarded = false; } | |||
138 | ||||
139 | private: | |||
140 | GuardedBlocks(GuardedBlocks &); // not implemented | |||
141 | void operator =(GuardedBlocks); // not implemented | |||
142 | ||||
143 | VtableFactory const & m_factory; | |||
144 | bool m_guarded; | |||
145 | }; | |||
146 | ||||
147 | VtableFactory::GuardedBlocks::~GuardedBlocks() { | |||
148 | if (m_guarded) { | |||
149 | for (iterator i(begin()); i != end(); ++i) { | |||
150 | m_factory.freeBlock(*i); | |||
151 | } | |||
152 | } | |||
153 | } | |||
154 | ||||
155 | class VtableFactory::BaseOffset { | |||
156 | public: | |||
157 | BaseOffset(typelib_InterfaceTypeDescription * type) { calculate(type, 0); } | |||
158 | ||||
159 | sal_Int32 getFunctionOffset(rtl::OUString const & name) const | |||
160 | { return m_map.find(name)->second; } | |||
161 | ||||
162 | private: | |||
163 | sal_Int32 calculate( | |||
164 | typelib_InterfaceTypeDescription * type, sal_Int32 offset); | |||
165 | ||||
166 | typedef boost::unordered_map< rtl::OUString, sal_Int32, rtl::OUStringHash > Map; | |||
167 | ||||
168 | Map m_map; | |||
169 | }; | |||
170 | ||||
171 | sal_Int32 VtableFactory::BaseOffset::calculate( | |||
172 | typelib_InterfaceTypeDescription * type, sal_Int32 offset) | |||
173 | { | |||
174 | rtl::OUString name(type->aBase.pTypeName); | |||
175 | if (m_map.find(name) == m_map.end()) { | |||
176 | for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) { | |||
177 | offset = calculate(type->ppBaseTypes[i], offset); | |||
178 | } | |||
179 | m_map.insert(Map::value_type(name, offset)); | |||
180 | typelib_typedescription_complete( | |||
181 | reinterpret_cast< typelib_TypeDescription ** >(&type)); | |||
182 | offset += bridges::cpp_uno::shared::getLocalFunctions(type); | |||
183 | } | |||
184 | return offset; | |||
185 | } | |||
186 | ||||
187 | VtableFactory::VtableFactory(): m_arena( | |||
188 | rtl_arena_create( | |||
189 | "bridges::cpp_uno::shared::VtableFactory", | |||
190 | sizeof (void *), // to satisfy alignment requirements | |||
191 | 0, reinterpret_cast< rtl_arena_type * >(-1), allocExec, freeExec, 0)) | |||
192 | { | |||
193 | if (m_arena == 0) { | |||
194 | throw std::bad_alloc(); | |||
195 | } | |||
196 | } | |||
197 | ||||
198 | VtableFactory::~VtableFactory() { | |||
199 | { | |||
200 | osl::MutexGuard guard(m_mutex); | |||
201 | for (Map::iterator i(m_map.begin()); i != m_map.end(); ++i) { | |||
202 | for (sal_Int32 j = 0; j < i->second.count; ++j) { | |||
203 | freeBlock(i->second.blocks[j]); | |||
204 | } | |||
205 | delete[] i->second.blocks; | |||
206 | } | |||
207 | } | |||
208 | rtl_arena_destroy(m_arena); | |||
209 | } | |||
210 | ||||
211 | VtableFactory::Vtables VtableFactory::getVtables( | |||
212 | typelib_InterfaceTypeDescription * type) | |||
213 | { | |||
214 | rtl::OUString name(type->aBase.pTypeName); | |||
215 | osl::MutexGuard guard(m_mutex); | |||
216 | Map::iterator i(m_map.find(name)); | |||
217 | if (i == m_map.end()) { | |||
| ||||
218 | GuardedBlocks blocks(*this); | |||
219 | createVtables(blocks, BaseOffset(type), type, true); | |||
220 | Vtables vtables; | |||
221 | OSL_ASSERT(blocks.size() <= SAL_MAX_INT32)do { if (true && (!(blocks.size() <= ((sal_Int32) 0x7FFFFFFF )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/usr/local/src/libreoffice/bridges/source/cpp_uno/shared/vtablefactory.cxx" ":" "221" ": "), "OSL_ASSERT: %s", "blocks.size() <= SAL_MAX_INT32" ); } } while (false); | |||
222 | vtables.count = static_cast< sal_Int32 >(blocks.size()); | |||
223 | bridges::cpp_uno::shared::GuardedArray< Block > guardedBlocks( | |||
224 | new Block[vtables.count]); | |||
225 | vtables.blocks = guardedBlocks.get(); | |||
226 | for (sal_Int32 j = 0; j < vtables.count; ++j) { | |||
227 | vtables.blocks[j] = blocks[j]; | |||
228 | } | |||
229 | i = m_map.insert(Map::value_type(name, vtables)).first; | |||
230 | guardedBlocks.release(); | |||
231 | blocks.unguard(); | |||
232 | } | |||
233 | return i->second; | |||
234 | } | |||
235 | ||||
236 | #ifdef USE_DOUBLE_MMAP | |||
237 | bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const | |||
238 | { | |||
239 | sal_Size size = getBlockSize(slotCount); | |||
240 | sal_Size pagesize = sysconf(_SC_PAGESIZE_SC_PAGESIZE); | |||
241 | block.size = (size + (pagesize - 1)) & ~(pagesize - 1); | |||
242 | block.start = block.exec = NULL__null; | |||
243 | block.fd = -1; | |||
244 | ||||
245 | osl::Security aSecurity; | |||
246 | rtl::OUString strDirectory; | |||
247 | rtl::OUString strURLDirectory; | |||
248 | if (aSecurity.getHomeDir(strURLDirectory)) | |||
249 | osl::File::getSystemPathFromFileURL(strURLDirectory, strDirectory); | |||
250 | ||||
251 | for (int i = strDirectory.isEmpty() ? 1 : 0; i < 2; ++i) | |||
252 | { | |||
253 | if (strDirectory.isEmpty()) | |||
254 | strDirectory = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/tmp" )(&("/tmp")[0]), ((sal_Int32)((sizeof ("/tmp") / sizeof (( "/tmp")[0]))-1)), (((rtl_TextEncoding) 11))); | |||
255 | ||||
256 | strDirectory += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/.execoooXXXXXX" )(&("/.execoooXXXXXX")[0]), ((sal_Int32)((sizeof ("/.execoooXXXXXX" ) / sizeof (("/.execoooXXXXXX")[0]))-1)), (((rtl_TextEncoding ) 11))); | |||
257 | rtl::OString aTmpName = rtl::OUStringToOString(strDirectory, osl_getThreadTextEncoding()); | |||
258 | char *tmpfname = new char[aTmpName.getLength()+1]; | |||
259 | strncpy(tmpfname, aTmpName.getStr(), aTmpName.getLength()+1); | |||
260 | if ((block.fd = mkstemp(tmpfname)) == -1) | |||
261 | fprintf(stderrstderr, "mkstemp(\"%s\") failed: %s\n", tmpfname, strerror(errno(*__errno_location ()))); | |||
262 | if (block.fd == -1) | |||
263 | { | |||
264 | delete[] tmpfname; | |||
265 | break; | |||
266 | } | |||
267 | unlink(tmpfname); | |||
268 | delete[] tmpfname; | |||
269 | #if defined(HAVE_POSIX_FALLOCATE1) | |||
270 | int err = posix_fallocate(block.fd, 0, block.size); | |||
271 | #else | |||
272 | int err = ftruncate(block.fd, block.size); | |||
273 | #endif | |||
274 | if (err != 0) | |||
275 | { | |||
276 | #if defined(HAVE_POSIX_FALLOCATE1) | |||
277 | SAL_WARN("bridges", "posix_fallocate failed with code " << err)do { if (true) { if (sizeof ::sal::detail::getResult( ::sal:: detail::StreamStart() << "posix_fallocate failed with code " << err) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("bridges"), ("/usr/local/src/libreoffice/bridges/source/cpp_uno/shared/vtablefactory.cxx" ":" "277" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "posix_fallocate failed with code " << err)); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "posix_fallocate failed with code " << err; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("bridges"), ("/usr/local/src/libreoffice/bridges/source/cpp_uno/shared/vtablefactory.cxx" ":" "277" ": "), sal_detail_stream); } } } while (false); | |||
278 | #else | |||
279 | SAL_WARN("bridges", "truncation of executable memory area failed with code " << err)do { if (true) { if (sizeof ::sal::detail::getResult( ::sal:: detail::StreamStart() << "truncation of executable memory area failed with code " << err) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("bridges"), ("/usr/local/src/libreoffice/bridges/source/cpp_uno/shared/vtablefactory.cxx" ":" "279" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "truncation of executable memory area failed with code " << err)); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "truncation of executable memory area failed with code " << err; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("bridges"), ("/usr/local/src/libreoffice/bridges/source/cpp_uno/shared/vtablefactory.cxx" ":" "279" ": "), sal_detail_stream); } } } while (false); | |||
280 | #endif | |||
281 | close(block.fd); | |||
282 | block.fd = -1; | |||
283 | break; | |||
284 | } | |||
285 | block.start = mmap(NULL__null, block.size, PROT_READ0x1 | PROT_WRITE0x2, MAP_SHARED0x01, block.fd, 0); | |||
286 | if (block.start== MAP_FAILED((void *) -1)) { | |||
287 | block.start = 0; | |||
288 | } | |||
289 | block.exec = mmap(NULL__null, block.size, PROT_READ0x1 | PROT_EXEC0x4, MAP_SHARED0x01, block.fd, 0); | |||
290 | if (block.exec == MAP_FAILED((void *) -1)) { | |||
291 | block.exec = 0; | |||
292 | } | |||
293 | ||||
294 | //All good | |||
295 | if (block.start && block.exec && block.fd != -1) | |||
296 | break; | |||
297 | ||||
298 | freeBlock(block); | |||
299 | ||||
300 | strDirectory = rtl::OUString(); | |||
301 | } | |||
302 | if (!block.start || !block.exec || block.fd == -1) | |||
303 | { | |||
304 | //Fall back to non-doublemmaped allocation | |||
305 | block.fd = -1; | |||
306 | block.start = block.exec = rtl_arena_alloc(m_arena, &block.size); | |||
307 | } | |||
308 | return (block.start != 0 && block.exec != 0); | |||
309 | } | |||
310 | ||||
311 | void VtableFactory::freeBlock(Block const & block) const { | |||
312 | //if the double-map failed we were allocated on the arena | |||
313 | if (block.fd == -1 && block.start == block.exec && block.start != NULL__null) | |||
314 | rtl_arena_free(m_arena, block.start, block.size); | |||
315 | else | |||
316 | { | |||
317 | if (block.start) munmap(block.start, block.size); | |||
318 | if (block.exec) munmap(block.exec, block.size); | |||
319 | if (block.fd != -1) close(block.fd); | |||
320 | } | |||
321 | } | |||
322 | #else | |||
323 | bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const | |||
324 | { | |||
325 | block.size = getBlockSize(slotCount); | |||
326 | block.start = rtl_arena_alloc(m_arena, &block.size); | |||
327 | return block.start != 0; | |||
328 | } | |||
329 | ||||
330 | void VtableFactory::freeBlock(Block const & block) const { | |||
331 | rtl_arena_free(m_arena, block.start, block.size); | |||
332 | } | |||
333 | #endif | |||
334 | ||||
335 | void VtableFactory::createVtables( | |||
336 | GuardedBlocks & blocks, BaseOffset const & baseOffset, | |||
337 | typelib_InterfaceTypeDescription * type, bool includePrimary) const | |||
338 | { | |||
339 | if (includePrimary) { | |||
340 | sal_Int32 slotCount | |||
341 | = bridges::cpp_uno::shared::getPrimaryFunctions(type); | |||
342 | Block block; | |||
343 | if (!createBlock(block, slotCount)) { | |||
344 | throw std::bad_alloc(); | |||
345 | } | |||
346 | try { | |||
347 | Slot * slots = initializeBlock(block.start, slotCount); | |||
348 | unsigned char * codeBegin = | |||
349 | reinterpret_cast< unsigned char * >(slots); | |||
350 | unsigned char * code = codeBegin; | |||
351 | sal_Int32 vtableOffset = blocks.size() * sizeof (Slot *); | |||
352 | for (typelib_InterfaceTypeDescription const * type2 = type; | |||
353 | type2 != 0; type2 = type2->pBaseTypeDescription) | |||
354 | { | |||
355 | code = addLocalFunctions( | |||
356 | &slots, code, | |||
357 | #ifdef USE_DOUBLE_MMAP | |||
358 | sal_IntPtr(block.exec) - sal_IntPtr(block.start), | |||
359 | #endif | |||
360 | type2, | |||
361 | baseOffset.getFunctionOffset(type2->aBase.pTypeName), | |||
362 | bridges::cpp_uno::shared::getLocalFunctions(type2), | |||
363 | vtableOffset); | |||
364 | } | |||
365 | flushCode(codeBegin, code); | |||
366 | #ifdef USE_DOUBLE_MMAP | |||
367 | //Finished generating block, swap writable pointer with executable | |||
368 | //pointer | |||
369 | ::std::swap(block.start, block.exec); | |||
370 | #endif | |||
371 | blocks.push_back(block); | |||
372 | } catch (...) { | |||
373 | freeBlock(block); | |||
374 | throw; | |||
375 | } | |||
376 | } | |||
377 | for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) { | |||
| ||||
378 | createVtables(blocks, baseOffset, type->ppBaseTypes[i], i != 0); | |||
379 | } | |||
380 | } | |||
381 | ||||
382 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |