Bug Summary

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')

Annotated Source Code

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
73using bridges::cpp_uno::shared::VtableFactory;
74
75namespace {
76
77extern "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
117extern "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
130class VtableFactory::GuardedBlocks: public std::vector< Block > {
131public:
132 GuardedBlocks(VtableFactory const & factory):
133 m_factory(factory), m_guarded(true) {}
134
135 ~GuardedBlocks();
136
137 void unguard() { m_guarded = false; }
138
139private:
140 GuardedBlocks(GuardedBlocks &); // not implemented
141 void operator =(GuardedBlocks); // not implemented
142
143 VtableFactory const & m_factory;
144 bool m_guarded;
145};
146
147VtableFactory::GuardedBlocks::~GuardedBlocks() {
148 if (m_guarded) {
149 for (iterator i(begin()); i != end(); ++i) {
150 m_factory.freeBlock(*i);
151 }
152 }
153}
154
155class VtableFactory::BaseOffset {
156public:
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
162private:
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
171sal_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
187VtableFactory::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
198VtableFactory::~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
211VtableFactory::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()) {
1
Taking true branch
218 GuardedBlocks blocks(*this);
219 createVtables(blocks, BaseOffset(type), type, true);
2
Calling 'createVtables'
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
237bool 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
311void 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
323bool 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
330void VtableFactory::freeBlock(Block const & block) const {
331 rtl_arena_free(m_arena, block.start, block.size);
332}
333#endif
334
335void VtableFactory::createVtables(
336 GuardedBlocks & blocks, BaseOffset const & baseOffset,
337 typelib_InterfaceTypeDescription * type, bool includePrimary) const
338{
339 if (includePrimary) {
3
Taking true branch
11
Taking true branch
340 sal_Int32 slotCount
341 = bridges::cpp_uno::shared::getPrimaryFunctions(type);
342 Block block;
343 if (!createBlock(block, slotCount)) {
4
Taking false branch
12
Taking false branch
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;
5
Loop condition is true. Entering loop body
6
Loop condition is false. Execution continues on line 365
14
Loop condition is false. Execution continues on line 365
353 type2 != 0; type2 = type2->pBaseTypeDescription)
13
Assuming 'type2' is equal to null
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) {
7
Loop condition is true. Entering loop body
8
Loop condition is true. Entering loop body
9
Loop condition is true. Entering loop body
15
Access to field 'nBaseTypes' results in a dereference of a null pointer (loaded from variable 'type')
378 createVtables(blocks, baseOffset, type->ppBaseTypes[i], i != 0);
10
Calling 'createVtables'
379 }
380}
381
382/* vim:set shiftwidth=4 softtabstop=4 expandtab: */