Bug Summary

File:cppu/source/uno/EnvStack.cxx
Location:line 340, column 13
Description:Access to field 'acquire' results in a dereference of a null pointer (loaded from variable 'pNextEnv')

Annotated Source Code

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include "uno/environment.hxx"
21
22#include "cppu/EnvDcp.hxx"
23#include "cppu/Enterable.hxx"
24
25#include "rtl/instance.hxx"
26
27#include "osl/thread.h"
28#include "osl/mutex.hxx"
29
30#include <boost/unordered_map.hpp>
31
32
33using namespace com::sun::star;
34
35
36struct SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) oslThreadIdentifier_equal
37{
38 bool operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const;
39};
40
41bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const
42{
43 bool result = s1 == s2;
44
45 return result;
46}
47
48
49struct SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) oslThreadIdentifier_hash
50{
51 size_t operator()(oslThreadIdentifier s1) const;
52};
53
54size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const
55{
56 return s1;
57}
58
59typedef ::boost::unordered_map<oslThreadIdentifier,
60 uno_Environment *,
61 oslThreadIdentifier_hash,
62 oslThreadIdentifier_equal> ThreadMap;
63
64namespace
65{
66 struct s_threadMap_mutex : public rtl::Static< osl::Mutex, s_threadMap_mutex > {};
67 struct s_threadMap : public rtl::Static< ThreadMap, s_threadMap > {};
68}
69
70static rtl::OUString s_uno_envDcp(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO)(&("uno")[0]), ((sal_Int32)((sizeof ("uno") / sizeof (("uno"
)[0]))-1)), (((rtl_TextEncoding) 11))
);
71
72static void s_setCurrent(uno_Environment * pEnv)
73{
74 oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL__null);
75
76 osl::MutexGuard guard(s_threadMap_mutex::get());
77 ThreadMap &rThreadMap = s_threadMap::get();
78 if (pEnv)
79 rThreadMap[threadId] = pEnv;
80
81 else
82 rThreadMap.erase(threadId);
83}
84
85static uno_Environment * s_getCurrent(void)
86{
87 uno_Environment * pEnv = NULL__null;
88
89 oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL__null);
90
91 osl::MutexGuard guard(s_threadMap_mutex::get());
92 ThreadMap &rThreadMap = s_threadMap::get();
93 ThreadMap::iterator iEnv = rThreadMap.find(threadId);
94 if(iEnv != rThreadMap.end())
95 pEnv = iEnv->second;
96
97 return pEnv;
98}
99
100
101extern "C" CPPU_DLLPUBLIC__attribute__ ((visibility("default"))) void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName)
102 SAL_THROW_EXTERN_C()throw ()
103{
104 if (*ppEnv)
105 {
106 (*ppEnv)->release(*ppEnv);
107 *ppEnv = NULL__null;
108 }
109
110 rtl::OUString currPurpose;
111
112 uno_Environment * pCurrEnv = s_getCurrent();
113 if (pCurrEnv) // no environment means no purpose
114 currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
115
116 if (pTypeName && rtl_uString_getLength(pTypeName))
117 {
118 rtl::OUString envDcp(pTypeName);
119 envDcp += currPurpose;
120
121 uno_getEnvironment(ppEnv, envDcp.pData, NULL__null);
122 }
123 else
124 {
125 if (pCurrEnv)
126 {
127 *ppEnv = pCurrEnv;
128 (*ppEnv)->acquire(*ppEnv);
129 }
130 else
131 uno_getEnvironment(ppEnv, s_uno_envDcp.pData, NULL__null);
132
133 }
134}
135
136static rtl::OUString s_getPrefix(rtl::OUString const & str1, rtl::OUString const & str2)
137{
138 sal_Int32 nIndex1 = 0;
139 sal_Int32 nIndex2 = 0;
140 sal_Int32 sim = 0;
141
142 rtl::OUString token1;
143 rtl::OUString token2;
144
145 do
146 {
147 token1 = str1.getToken(0, ':', nIndex1);
148 token2 = str2.getToken(0, ':', nIndex2);
149
150 if (token1.equals(token2))
151 sim += token1.getLength() + 1;
152 }
153 while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1.equals(token2));
154
155 rtl::OUString result;
156
157 if (sim)
158 result = str1.copy(0, sim - 1);
159
160 return result;
161}
162
163static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv)
164{
165 int res = 0;
166
167 rtl::OUString nextPurpose;
168
169 rtl::OUString currPurpose;
170 if (pCurrEnv)
171 currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
172
173 rtl::OUString targetPurpose;
174 if (pTargetEnv)
175 targetPurpose = cppu::EnvDcp::getPurpose(pTargetEnv->pTypeName);
176
177 rtl::OUString intermPurpose(s_getPrefix(currPurpose, targetPurpose));
178 if (currPurpose.getLength() > intermPurpose.getLength())
179 {
180 sal_Int32 idx = currPurpose.lastIndexOf(':');
181 nextPurpose = currPurpose.copy(0, idx);
182
183 res = -1;
184 }
185 else if (intermPurpose.getLength() < targetPurpose.getLength())
186 {
187 sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1);
188 if (idx == -1)
189 nextPurpose = targetPurpose;
190
191 else
192 nextPurpose = targetPurpose.copy(0, idx);
193
194 res = 1;
195 }
196
197 if (!nextPurpose.isEmpty())
198 {
199 rtl::OUString next_envDcp(s_uno_envDcp);
200 next_envDcp += nextPurpose;
201
202 uno_getEnvironment(ppEnv, next_envDcp.pData, NULL__null);
203 }
204 else
205 {
206 if (*ppEnv)
207 (*ppEnv)->release(*ppEnv);
208
209 *ppEnv = NULL__null;
210 }
211
212 return res;
213}
214
215extern "C" { static void s_pull(va_list * pParam)
216{
217 uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *)__builtin_va_arg(*pParam, uno_EnvCallee *);
218 va_list * pXparam = va_arg(*pParam, va_list *)__builtin_va_arg(*pParam, va_list *);
219
220 pCallee(pXparam);
221}}
222
223static void s_callInto_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
224{
225 cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
226 if (pEnterable)
227 pEnterable->callInto(s_pull, pCallee, pParam);
228
229 else
230 pCallee(pParam);
231}
232
233static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
234{
235 va_list param;
236
237 va_start(param, pCallee)__builtin_va_start(param, pCallee);
238 s_callInto_v(pEnv, pCallee, &param);
239 va_end(param)__builtin_va_end(param);
240}
241
242static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
243{
244 cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
245 if (pEnterable)
246 pEnterable->callOut_v(pCallee, pParam);
247
248 else
249 pCallee(pParam);
250}
251
252static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
253{
254 va_list param;
255
256 va_start(param, pCallee)__builtin_va_start(param, pCallee);
257 s_callOut_v(pEnv, pCallee, &param);
258 va_end(param)__builtin_va_end(param);
259}
260
261static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list *);
262
263extern "C" { static void s_environment_invoke_vv(va_list * pParam)
264{
265 uno_Environment * pCurrEnv = va_arg(*pParam, uno_Environment *)__builtin_va_arg(*pParam, uno_Environment *);
266 uno_Environment * pTargetEnv = va_arg(*pParam, uno_Environment *)__builtin_va_arg(*pParam, uno_Environment *);
267 uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *)__builtin_va_arg(*pParam, uno_EnvCallee *);
268 va_list * pXparam = va_arg(*pParam, va_list *)__builtin_va_arg(*pParam, va_list *);
269
270 s_environment_invoke_v(pCurrEnv, pTargetEnv, pCallee, pXparam);
271}}
272
273static void s_environment_invoke_v(uno_Environment * pCurrEnv, uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
274{
275 uno_Environment * pNextEnv = NULL__null;
276 switch(s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv))
277 {
278 case -1:
279 s_setCurrent(pNextEnv);
280 s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
281 s_setCurrent(pCurrEnv);
282 break;
283
284 case 0: {
285 uno_Environment * hld = s_getCurrent();
286 s_setCurrent(pCurrEnv);
287 pCallee(pParam);
288 s_setCurrent(hld);
289 }
290 break;
291
292 case 1:
293 s_setCurrent(pNextEnv);
294 s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
295 s_setCurrent(pCurrEnv);
296 break;
297 }
298
299 if (pNextEnv)
300 pNextEnv->release(pNextEnv);
301}
302
303extern "C" CPPU_DLLPUBLIC__attribute__ ((visibility("default"))) void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
304 SAL_THROW_EXTERN_C()throw ()
305{
306 s_environment_invoke_v(s_getCurrent(), pTargetEnv, pCallee, pParam);
307}
308
309extern "C" CPPU_DLLPUBLIC__attribute__ ((visibility("default"))) void SAL_CALL uno_Environment_invoke(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
310 SAL_THROW_EXTERN_C()throw ()
311{
312 va_list param;
313
314 va_start(param, pCallee)__builtin_va_start(param, pCallee);
315 uno_Environment_invoke_v(pEnv, pCallee, &param);
316 va_end(param)__builtin_va_end(param);
317}
318
319extern "C" CPPU_DLLPUBLIC__attribute__ ((visibility("default"))) void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv)
320 SAL_THROW_EXTERN_C()throw ()
321{
322 uno_Environment * pNextEnv = NULL__null;
323 uno_Environment * pCurrEnv = s_getCurrent();
324
325 int res;
326 while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0)
1
Loop condition is true. Entering loop body
5
Loop condition is true. Entering loop body
9
Loop condition is true. Entering loop body
13
Loop condition is true. Entering loop body
327 {
328 cppu::Enterable * pEnterable;
329
330 switch(res)
2
Control jumps to 'case 1:' at line 339
6
Control jumps to 'case 1:' at line 339
10
Control jumps to 'case 1:' at line 339
14
Control jumps to 'case 1:' at line 339
331 {
332 case -1:
333 pEnterable = reinterpret_cast<cppu::Enterable *>(pCurrEnv->pReserved);
334 if (pEnterable)
335 pEnterable->leave();
336 pCurrEnv->release(pCurrEnv);
337 break;
338
339 case 1:
340 pNextEnv->acquire(pNextEnv);
15
Access to field 'acquire' results in a dereference of a null pointer (loaded from variable 'pNextEnv')
341 pEnterable = reinterpret_cast<cppu::Enterable *>(pNextEnv->pReserved);
342 if (pEnterable)
3
Taking false branch
7
Taking false branch
11
Taking false branch
343 pEnterable->enter();
344 break;
4
Execution continues on line 347
8
Execution continues on line 347
12
Execution continues on line 347
345 }
346
347 s_setCurrent(pNextEnv);
348 pCurrEnv = pNextEnv;
349 }
350}
351
352CPPU_DLLPUBLIC__attribute__ ((visibility("default"))) int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason)
353 SAL_THROW_EXTERN_C()throw ()
354{
355 int result = 1;
356
357 rtl::OUString typeName(cppu::EnvDcp::getTypeName(pEnv->pTypeName));
358 if (typeName.equals(s_uno_envDcp))
359 {
360 cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
361 if (pEnterable)
362 result = pEnterable->isValid((rtl::OUString *)pReason);
363 }
364 else
365 {
366 rtl::OUString envDcp(s_uno_envDcp);
367 envDcp += cppu::EnvDcp::getPurpose(pEnv->pTypeName);
368
369 uno::Environment env(envDcp);
370
371 result = env.isValid((rtl::OUString *)pReason);
372 }
373
374 return result;
375}
376
377/* vim:set shiftwidth=4 softtabstop=4 expandtab: */