| 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: */ |