Line data 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 :
21 : #ifdef WNT
22 : # include <stdio.h>
23 : # include <sys/stat.h>
24 : # include <windows.h>
25 : #endif
26 :
27 : #ifdef ANDROID
28 : # include <dlfcn.h>
29 : #endif
30 :
31 : #include <string.h>
32 :
33 : #include "boost/scoped_array.hpp"
34 : #include "config_options.h"
35 : #include "osl/diagnose.h"
36 : #include "rtl/ustring.hxx"
37 : #include "rtl/ustrbuf.hxx"
38 : #include "osl/module.hxx"
39 : #include "osl/mutex.hxx"
40 : #include "osl/process.h"
41 : #include "osl/thread.hxx"
42 : #include "osl/file.hxx"
43 : #include "rtl/instance.hxx"
44 : #include "osl/getglobalmutex.hxx"
45 : #include <setjmp.h>
46 : #include <signal.h>
47 : #include <stack>
48 :
49 : #include "jni.h"
50 : #include "rtl/byteseq.hxx"
51 : #include "vendorplugin.hxx"
52 : #include "util.hxx"
53 : #include "sunversion.hxx"
54 : #include "vendorlist.hxx"
55 : #include "diagnostics.h"
56 :
57 : #ifdef ANDROID
58 : #include <osl/detail/android-bootstrap.h>
59 : #else
60 : #if !ENABLE_RUNTIME_OPTIMIZATIONS
61 : #define FORCE_INTERPRETED 1
62 : #elif defined HAVE_VALGRIND_HEADERS
63 : #include <valgrind/valgrind.h>
64 : #define FORCE_INTERPRETED RUNNING_ON_VALGRIND
65 : #else
66 : #define FORCE_INTERPRETED 0
67 : #endif
68 : #endif
69 :
70 : #if defined LINUX && defined X86
71 : #include <sys/resource.h>
72 : #endif
73 :
74 : using namespace osl;
75 : using namespace std;
76 : using namespace jfw_plugin;
77 :
78 :
79 : namespace {
80 :
81 : struct PluginMutex: public ::rtl::Static<osl::Mutex, PluginMutex> {};
82 :
83 : #if defined(UNX) && !defined(ANDROID)
84 3 : OString getPluginJarPath(
85 : const OUString & sVendor,
86 : const OUString& sLocation,
87 : const OUString& sVersion)
88 : {
89 3 : OString ret;
90 6 : OUString sName1("javaplugin.jar");
91 6 : OUString sName2("plugin.jar");
92 6 : OUString sPath;
93 3 : if ( sVendor == "Sun Microsystems Inc." )
94 : {
95 0 : SunVersion ver142("1.4.2-ea");
96 0 : SunVersion ver150("1.5.0-ea");
97 0 : SunVersion ver(sVersion);
98 : OSL_ASSERT(ver142 && ver150 && ver);
99 :
100 0 : OUString sName;
101 0 : if (ver < ver142)
102 : {
103 0 : sName = sName1;
104 : }
105 0 : else if (ver < ver150)
106 : {//this will cause ea, beta etc. to have plugin.jar in path.
107 : //but this does not harm. 1.5.0-beta < 1.5.0
108 0 : sName = sName2;
109 : }
110 0 : if (!sName.isEmpty())
111 : {
112 0 : sName = sLocation + "/lib/" + sName;
113 0 : OSL_VERIFY(
114 : osl_getSystemPathFromFileURL(sName.pData, & sPath.pData)
115 : == osl_File_E_None);
116 0 : }
117 : }
118 : else
119 : {
120 3 : char sep[] = {SAL_PATHSEPARATOR, 0};
121 3 : OUString sName(sLocation + "/lib/" + sName1);
122 6 : OUString sPath1;
123 6 : OUString sPath2;
124 3 : if (osl_getSystemPathFromFileURL(sName.pData, & sPath1.pData)
125 : == osl_File_E_None)
126 : {
127 3 : sName = sLocation + "/lib/" + sName2;
128 3 : if (osl_getSystemPathFromFileURL(sName.pData, & sPath2.pData)
129 : == osl_File_E_None)
130 : {
131 3 : sPath = sPath1 + OUString::createFromAscii(sep) + sPath2;
132 : }
133 : }
134 3 : OSL_ASSERT(!sPath.isEmpty());
135 : }
136 3 : ret = OUStringToOString(sPath, osl_getThreadTextEncoding());
137 :
138 6 : return ret;
139 : }
140 : #endif // UNX
141 :
142 :
143 77 : JavaInfo* createJavaInfo(const rtl::Reference<VendorBase> & info)
144 : {
145 77 : JavaInfo* pInfo = static_cast<JavaInfo*>(rtl_allocateMemory(sizeof(JavaInfo)));
146 77 : if (pInfo == NULL)
147 0 : return NULL;
148 77 : OUString sVendor = info->getVendor();
149 77 : pInfo->sVendor = sVendor.pData;
150 77 : rtl_uString_acquire(sVendor.pData);
151 154 : OUString sHome = info->getHome();
152 77 : pInfo->sLocation = sHome.pData;
153 77 : rtl_uString_acquire(pInfo->sLocation);
154 154 : OUString sVersion = info->getVersion();
155 77 : pInfo->sVersion = sVersion.pData;
156 77 : rtl_uString_acquire(pInfo->sVersion);
157 77 : pInfo->nFeatures = info->supportsAccessibility() ? 1 : 0;
158 77 : pInfo->nRequirements = info->needsRestart() ? JFW_REQUIRE_NEEDRESTART : 0;
159 154 : OUStringBuffer buf(1024);
160 77 : buf.append(info->getRuntimeLibrary());
161 77 : if (!info->getLibraryPath().isEmpty())
162 : {
163 77 : buf.appendAscii("\n");
164 77 : buf.append(info->getLibraryPath());
165 77 : buf.appendAscii("\n");
166 : }
167 :
168 154 : OUString sVendorData = buf.makeStringAndClear();
169 : rtl::ByteSequence byteSeq( reinterpret_cast<sal_Int8*>(sVendorData.pData->buffer),
170 154 : sVendorData.getLength() * sizeof(sal_Unicode));
171 77 : pInfo->arVendorData = byteSeq.get();
172 77 : rtl_byte_sequence_acquire(pInfo->arVendorData);
173 :
174 154 : return pInfo;
175 : }
176 :
177 77 : OUString getRuntimeLib(const rtl::ByteSequence & data)
178 : {
179 77 : const sal_Unicode* chars = reinterpret_cast<sal_Unicode const *>(data.getConstArray());
180 77 : sal_Int32 len = data.getLength();
181 77 : OUString sData(chars, len / 2);
182 : //the runtime lib is on the first line
183 77 : sal_Int32 index = 0;
184 77 : OUString aToken = sData.getToken( 0, '\n', index);
185 :
186 77 : return aToken;
187 : }
188 :
189 : jmp_buf jmp_jvm_abort;
190 : sig_atomic_t g_bInGetJavaVM = 0;
191 :
192 0 : extern "C" void JNICALL abort_handler()
193 : {
194 : // If we are within JNI_CreateJavaVM then we jump back into getJavaVM
195 0 : if( g_bInGetJavaVM != 0 )
196 : {
197 0 : fprintf( stderr, "JavaVM: JNI_CreateJavaVM called _exit, caught by abort_handler in javavm.cxx\n");
198 0 : longjmp( jmp_jvm_abort, 0);
199 : }
200 0 : }
201 :
202 : /** helper function to check Java version requirements
203 :
204 : This function checks if the Java version of the given VendorBase
205 : meets the given Java version requirements.
206 :
207 : @param aVendorInfo
208 : [in] the object to be inspected whether it meets the version requirements
209 : @param sMinVersion
210 : [in] represents the minimum version of a JRE. The string can be empty.
211 : @param sMaxVersion
212 : [in] represents the maximum version of a JRE. The string can be empty.
213 : @param arExcludeList
214 : [in] contains a list of "bad" versions. JREs which have one of these
215 : versions must not be returned by this function. It can be NULL.
216 : @param nLenList
217 : [in] the number of version strings contained in <code>arExcludeList</code>.
218 :
219 : @return
220 : JFW_PLUGIN_E_NONE the function ran successfully and the version requirements are met
221 : JFW_PLUGIN_E_FAILED_VERSION at least one of the version requirements (minVersion,
222 : maxVersion, excludeVersions) was violated
223 : JFW_PLUGIN_E_WRONG_VERSION_FORMAT the version strings in
224 : <code>sMinVersion,sMaxVersion,arExcludeList</code> are not recognized as valid
225 : version strings.
226 :
227 : */
228 77 : javaPluginError checkJavaVersionRequirements(
229 : rtl::Reference<VendorBase> const & aVendorInfo,
230 : OUString const& sMinVersion,
231 : OUString const& sMaxVersion,
232 : rtl_uString * * arExcludeList,
233 : sal_Int32 nLenList)
234 : {
235 77 : if (!sMinVersion.isEmpty())
236 : {
237 : try
238 : {
239 77 : if (aVendorInfo->compareVersions(sMinVersion) < 0)
240 0 : return JFW_PLUGIN_E_FAILED_VERSION;
241 : }
242 0 : catch (MalformedVersionException&)
243 : {
244 : //The minVersion was not recognized as valid for this vendor.
245 : JFW_ENSURE(
246 : false,
247 : "[Java framework]sunjavaplugin does not know version: "
248 : + sMinVersion + " for vendor: " + aVendorInfo->getVendor()
249 : + " .Check minimum Version." );
250 0 : return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
251 : }
252 : }
253 :
254 77 : if (!sMaxVersion.isEmpty())
255 : {
256 : try
257 : {
258 0 : if (aVendorInfo->compareVersions(sMaxVersion) > 0)
259 0 : return JFW_PLUGIN_E_FAILED_VERSION;
260 : }
261 0 : catch (MalformedVersionException&)
262 : {
263 : //The maxVersion was not recognized as valid for this vendor.
264 : JFW_ENSURE(
265 : false,
266 : "[Java framework]sunjavaplugin does not know version: "
267 : + sMaxVersion + " for vendor: " + aVendorInfo->getVendor()
268 : + " .Check maximum Version." );
269 0 : return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
270 : }
271 : }
272 :
273 77 : for (int i = 0; i < nLenList; i++)
274 : {
275 0 : OUString sExVer(arExcludeList[i]);
276 : try
277 : {
278 0 : if (aVendorInfo->compareVersions(sExVer) == 0)
279 0 : return JFW_PLUGIN_E_FAILED_VERSION;
280 : }
281 0 : catch (MalformedVersionException&)
282 : {
283 : //The excluded version was not recognized as valid for this vendor.
284 : JFW_ENSURE(
285 : false,
286 : "[Java framework]sunjavaplugin does not know version: "
287 : + sExVer + " for vendor: " + aVendorInfo->getVendor()
288 : + " .Check excluded versions." );
289 0 : return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
290 : }
291 0 : }
292 :
293 77 : return JFW_PLUGIN_E_NONE;
294 : }
295 :
296 : }
297 :
298 0 : javaPluginError jfw_plugin_getAllJavaInfos(
299 : bool checkJavaHomeAndPath,
300 : OUString const& sVendor,
301 : OUString const& sMinVersion,
302 : OUString const& sMaxVersion,
303 : rtl_uString * *arExcludeList,
304 : sal_Int32 nLenList,
305 : JavaInfo*** parJavaInfo,
306 : sal_Int32 *nLenInfoList,
307 : std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos)
308 : {
309 : OSL_ASSERT(parJavaInfo);
310 : OSL_ASSERT(nLenInfoList);
311 0 : if (!parJavaInfo || !nLenInfoList)
312 0 : return JFW_PLUGIN_E_INVALID_ARG;
313 :
314 : //nLenlist contains the number of elements in arExcludeList.
315 : //If no exclude list is provided then nLenList must be 0
316 : OSL_ASSERT( ! (arExcludeList == NULL && nLenList > 0));
317 0 : if (arExcludeList == NULL && nLenList > 0)
318 0 : return JFW_PLUGIN_E_INVALID_ARG;
319 :
320 : OSL_ASSERT(!sVendor.isEmpty());
321 0 : if (sVendor.isEmpty())
322 0 : return JFW_PLUGIN_E_INVALID_ARG;
323 :
324 0 : JavaInfo** arInfo = NULL;
325 :
326 : //Find all JREs
327 : vector<rtl::Reference<VendorBase> > vecInfos =
328 0 : addAllJREInfos(checkJavaHomeAndPath, infos);
329 0 : vector<rtl::Reference<VendorBase> > vecVerifiedInfos;
330 :
331 : typedef vector<rtl::Reference<VendorBase> >::iterator it;
332 0 : for (it i= vecInfos.begin(); i != vecInfos.end(); ++i)
333 : {
334 0 : const rtl::Reference<VendorBase>& cur = *i;
335 :
336 0 : if (!sVendor.equals(cur->getVendor()))
337 0 : continue;
338 :
339 : javaPluginError err = checkJavaVersionRequirements(
340 0 : cur, sMinVersion, sMaxVersion, arExcludeList, nLenList);
341 :
342 0 : if (err == JFW_PLUGIN_E_FAILED_VERSION)
343 0 : continue;
344 0 : else if (err == JFW_PLUGIN_E_WRONG_VERSION_FORMAT)
345 0 : return err;
346 :
347 0 : vecVerifiedInfos.push_back(*i);
348 : }
349 : //Now vecVerifiedInfos contains all those JREs which meet the version requirements
350 : //Transfer them into the array that is passed out.
351 0 : arInfo = static_cast<JavaInfo**>(rtl_allocateMemory(vecVerifiedInfos.size() * sizeof (JavaInfo*)));
352 0 : int j = 0;
353 : typedef vector<rtl::Reference<VendorBase> >::const_iterator cit;
354 0 : for (cit ii = vecVerifiedInfos.begin(); ii != vecVerifiedInfos.end(); ++ii, ++j)
355 : {
356 0 : arInfo[j] = createJavaInfo(*ii);
357 : }
358 0 : *nLenInfoList = vecVerifiedInfos.size();
359 :
360 :
361 0 : *parJavaInfo = arInfo;
362 0 : return JFW_PLUGIN_E_NONE;
363 : }
364 :
365 146 : javaPluginError jfw_plugin_getJavaInfoByPath(
366 : OUString const& sPath,
367 : OUString const& sVendor,
368 : OUString const& sMinVersion,
369 : OUString const& sMaxVersion,
370 : rtl_uString * *arExcludeList,
371 : sal_Int32 nLenList,
372 : JavaInfo ** ppInfo)
373 : {
374 146 : if (!ppInfo)
375 0 : return JFW_PLUGIN_E_INVALID_ARG;
376 : OSL_ASSERT(!sPath.isEmpty());
377 146 : if (sPath.isEmpty())
378 0 : return JFW_PLUGIN_E_INVALID_ARG;
379 :
380 : //nLenlist contains the number of elements in arExcludeList.
381 : //If no exclude list is provided then nLenList must be 0
382 : OSL_ASSERT( ! (arExcludeList == NULL && nLenList > 0));
383 146 : if (arExcludeList == NULL && nLenList > 0)
384 0 : return JFW_PLUGIN_E_INVALID_ARG;
385 :
386 : OSL_ASSERT(!sVendor.isEmpty());
387 146 : if (sVendor.isEmpty())
388 0 : return JFW_PLUGIN_E_INVALID_ARG;
389 :
390 146 : rtl::Reference<VendorBase> aVendorInfo = getJREInfoByPath(sPath);
391 146 : if (!aVendorInfo.is())
392 0 : return JFW_PLUGIN_E_NO_JRE;
393 :
394 : //Check if the detected JRE matches the version requirements
395 146 : if (!sVendor.equals(aVendorInfo->getVendor()))
396 73 : return JFW_PLUGIN_E_NO_JRE;
397 : javaPluginError errorcode = checkJavaVersionRequirements(
398 73 : aVendorInfo, sMinVersion, sMaxVersion, arExcludeList, nLenList);
399 :
400 73 : if (errorcode == JFW_PLUGIN_E_NONE)
401 73 : *ppInfo = createJavaInfo(aVendorInfo);
402 :
403 73 : return errorcode;
404 : }
405 :
406 4 : javaPluginError jfw_plugin_getJavaInfoFromJavaHome(
407 : std::vector<pair<OUString, jfw::VersionInfo>> const& vecVendorInfos,
408 : JavaInfo ** ppInfo, std::vector<rtl::Reference<VendorBase>> & infos)
409 : {
410 4 : if (!ppInfo)
411 0 : return JFW_PLUGIN_E_INVALID_ARG;
412 :
413 4 : std::vector<rtl::Reference<VendorBase>> infoJavaHome;
414 4 : addJavaInfoFromJavaHome(infos, infoJavaHome);
415 :
416 4 : if (infoJavaHome.empty())
417 0 : return JFW_PLUGIN_E_NO_JRE;
418 : assert(infoJavaHome.size() == 1);
419 :
420 : //Check if the detected JRE matches the version requirements
421 : typedef std::vector<pair<OUString, jfw::VersionInfo>>::const_iterator ci_pl;
422 8 : for (ci_pl vendorInfo = vecVendorInfos.begin(); vendorInfo != vecVendorInfos.end(); ++vendorInfo)
423 : {
424 8 : const OUString& vendor = vendorInfo->first;
425 8 : jfw::VersionInfo versionInfo = vendorInfo->second;
426 :
427 8 : if (vendor.equals(infoJavaHome[0]->getVendor()))
428 : {
429 : javaPluginError errorcode = checkJavaVersionRequirements(
430 4 : infoJavaHome[0],
431 : versionInfo.sMinVersion,
432 : versionInfo.sMaxVersion,
433 : versionInfo.getExcludeVersions(),
434 8 : versionInfo.getExcludeVersionSize());
435 :
436 4 : if (errorcode == JFW_PLUGIN_E_NONE)
437 : {
438 4 : *ppInfo = createJavaInfo(infoJavaHome[0]);
439 4 : return JFW_PLUGIN_E_NONE;
440 : }
441 : }
442 4 : }
443 :
444 0 : return JFW_PLUGIN_E_NO_JRE;
445 : }
446 :
447 0 : javaPluginError jfw_plugin_getJavaInfosFromPath(
448 : std::vector<std::pair<OUString, jfw::VersionInfo>> const& vecVendorInfos,
449 : std::vector<JavaInfo*> & javaInfosFromPath,
450 : std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos)
451 : {
452 : // find JREs from PATH
453 0 : vector<rtl::Reference<VendorBase>> vecInfosFromPath;
454 0 : addJavaInfosFromPath(infos, vecInfosFromPath);
455 :
456 0 : vector<JavaInfo*> vecVerifiedInfos;
457 :
458 : // copy infos of JREs that meet version requirements to vecVerifiedInfos
459 : typedef vector<rtl::Reference<VendorBase> >::iterator it;
460 0 : for (it i= vecInfosFromPath.begin(); i != vecInfosFromPath.end(); ++i)
461 : {
462 0 : const rtl::Reference<VendorBase>& currentInfo = *i;
463 :
464 : typedef std::vector<pair<OUString, jfw::VersionInfo>>::const_iterator ci_pl;
465 0 : for (ci_pl vendorInfo = vecVendorInfos.begin(); vendorInfo != vecVendorInfos.end(); ++vendorInfo)
466 : {
467 0 : const OUString& vendor = vendorInfo->first;
468 0 : jfw::VersionInfo versionInfo = vendorInfo->second;
469 :
470 0 : if (vendor.equals(currentInfo->getVendor()))
471 : {
472 : javaPluginError errorcode = checkJavaVersionRequirements(
473 : currentInfo,
474 : versionInfo.sMinVersion,
475 : versionInfo.sMaxVersion,
476 : versionInfo.getExcludeVersions(),
477 0 : versionInfo.getExcludeVersionSize());
478 :
479 0 : if (errorcode == JFW_PLUGIN_E_NONE)
480 : {
481 0 : vecVerifiedInfos.push_back(createJavaInfo(currentInfo));
482 : }
483 : }
484 0 : }
485 : }
486 :
487 0 : if (vecVerifiedInfos.empty())
488 0 : return JFW_PLUGIN_E_NO_JRE;
489 :
490 0 : javaInfosFromPath = vecVerifiedInfos;
491 :
492 0 : return JFW_PLUGIN_E_NONE;
493 : }
494 :
495 :
496 :
497 :
498 : #if defined(WNT)
499 :
500 : // Load msvcr71.dll using an explicit full path from where it is
501 : // present as bundled with the JRE. In case it is not found where we
502 : // think it should be, do nothing, and just let the implicit loading
503 : // that happens when loading the JVM take care of it.
504 :
505 : static void load_msvcr(LPCWSTR jvm_dll, wchar_t const* msvcr)
506 : {
507 : wchar_t msvcr_dll[MAX_PATH];
508 : wchar_t *slash;
509 :
510 : if (wcslen(jvm_dll) > MAX_PATH - 15)
511 : return;
512 :
513 : wcscpy(msvcr_dll, jvm_dll);
514 :
515 : // First check if msvcr71.dll is in the same folder as jvm.dll. It
516 : // normally isn't, at least up to 1.6.0_22, but who knows if it
517 : // might be in the future.
518 : slash = wcsrchr(msvcr_dll, L'\\');
519 :
520 : if (!slash)
521 : {
522 : // Huh, weird path to jvm.dll. Oh well.
523 : return;
524 : }
525 :
526 : wcscpy(slash+1, msvcr);
527 : if (LoadLibraryW(msvcr_dll))
528 : return;
529 :
530 : // Then check if msvcr71.dll is in the parent folder of where
531 : // jvm.dll is. That is currently (1.6.0_22) as far as I know the
532 : // normal case.
533 : *slash = 0;
534 : slash = wcsrchr(msvcr_dll, L'\\');
535 :
536 : if (!slash)
537 : return;
538 :
539 : wcscpy(slash+1, msvcr);
540 : LoadLibraryW(msvcr_dll);
541 : }
542 :
543 : // Check if the jvm DLL imports msvcr71.dll, and in that case try
544 : // loading it explicitly. In case something goes wrong, do nothing,
545 : // and just let the implicit loading try to take care of it.
546 : static void do_msvcr_magic(rtl_uString *jvm_dll)
547 : {
548 : rtl_uString* Module(0);
549 : struct stat st;
550 :
551 : oslFileError nError = osl_getSystemPathFromFileURL(jvm_dll, &Module);
552 :
553 : if ( osl_File_E_None != nError )
554 : rtl_uString_assign(&Module, jvm_dll);
555 :
556 : FILE *f = _wfopen(reinterpret_cast<LPCWSTR>(Module->buffer), L"rb");
557 :
558 : if (fstat(fileno(f), &st) == -1)
559 : {
560 : fclose(f);
561 : return;
562 : }
563 :
564 : PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER) malloc(st.st_size);
565 :
566 : if (fread(dos_hdr, st.st_size, 1, f) != 1 ||
567 : memcmp(dos_hdr, "MZ", 2) != 0 ||
568 : dos_hdr->e_lfanew < 0 ||
569 : dos_hdr->e_lfanew > (LONG) (st.st_size - sizeof(IMAGE_NT_HEADERS)))
570 : {
571 : free(dos_hdr);
572 : fclose(f);
573 : return;
574 : }
575 :
576 : fclose(f);
577 :
578 : IMAGE_NT_HEADERS *nt_hdr = (IMAGE_NT_HEADERS *) ((char *)dos_hdr + dos_hdr->e_lfanew);
579 :
580 : DWORD importsVA = nt_hdr->OptionalHeader
581 : .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
582 : // first determine Virtual-to-File-address mapping for the section
583 : // that contains the import directory
584 : IMAGE_SECTION_HEADER *sections = IMAGE_FIRST_SECTION(nt_hdr);
585 : ptrdiff_t VAtoPhys = -1;
586 : for (int i = 0; i < nt_hdr->FileHeader.NumberOfSections; ++i)
587 : {
588 : if (sections->VirtualAddress <= importsVA &&
589 : importsVA < sections->VirtualAddress + sections->SizeOfRawData)
590 : {
591 : VAtoPhys = sections->PointerToRawData - sections->VirtualAddress;
592 : break;
593 : }
594 : ++sections;
595 : }
596 : if (-1 == VAtoPhys) // not found?
597 : {
598 : free(dos_hdr);
599 : return;
600 : }
601 : IMAGE_IMPORT_DESCRIPTOR *imports =
602 : (IMAGE_IMPORT_DESCRIPTOR *) ((char *) dos_hdr + importsVA + VAtoPhys);
603 :
604 : while (imports <= (IMAGE_IMPORT_DESCRIPTOR *) ((char *) dos_hdr + st.st_size - sizeof (IMAGE_IMPORT_DESCRIPTOR)) &&
605 : imports->Name != 0 &&
606 : imports->Name + VAtoPhys < (DWORD) st.st_size)
607 : {
608 : static struct { char const * name; wchar_t const * wname; } msvcrts[] =
609 : {
610 : { "msvcr71.dll" , L"msvcr71.dll" },
611 : { "msvcr100.dll", L"msvcr100.dll" },
612 : };
613 : char const* importName = (char *) dos_hdr + imports->Name + VAtoPhys;
614 : for (size_t i = 0; i < SAL_N_ELEMENTS(msvcrts); ++i)
615 : {
616 : if (0 == strnicmp(importName,
617 : // Intentional strlen() + 1 here to include terminating zero
618 : msvcrts[i].name, strlen(msvcrts[i].name) + 1))
619 : {
620 : load_msvcr(reinterpret_cast<LPCWSTR>(Module->buffer),
621 : msvcrts[i].wname);
622 : free(dos_hdr);
623 : return;
624 : }
625 : }
626 : imports++;
627 : }
628 :
629 : free(dos_hdr);
630 : }
631 :
632 : #endif
633 :
634 : /** starts a Java Virtual Machine.
635 : <p>
636 : The function shall ensure, that the VM does not abort the process
637 : during instantiation.
638 : </p>
639 : */
640 7 : javaPluginError jfw_plugin_startJavaVirtualMachine(
641 : const JavaInfo *pInfo,
642 : const JavaVMOption* arOptions,
643 : sal_Int32 cOptions,
644 : JavaVM ** ppVm,
645 : JNIEnv ** ppEnv)
646 : {
647 : // unless guard is volatile the following warning occurs on gcc:
648 : // warning: variable 't' might be clobbered by `longjmp' or `vfork'
649 7 : volatile osl::MutexGuard guard(PluginMutex::get());
650 : // unless errorcode is volatile the following warning occurs on gcc:
651 : // warning: variable 'errorcode' might be clobbered by `longjmp' or `vfork'
652 7 : volatile javaPluginError errorcode = JFW_PLUGIN_E_NONE;
653 7 : if ( pInfo == NULL || ppVm == NULL || ppEnv == NULL)
654 0 : return JFW_PLUGIN_E_INVALID_ARG;
655 : //Check if the Vendor (pInfo->sVendor) is supported by this plugin
656 7 : if ( ! isVendorSupported(pInfo->sVendor))
657 0 : return JFW_PLUGIN_E_WRONG_VENDOR;
658 14 : OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
659 : JFW_TRACE2("Using Java runtime library: " << sRuntimeLib);
660 :
661 : #ifndef ANDROID
662 : // On linux we load jvm with RTLD_GLOBAL. This is necessary for debugging, because
663 : // libjdwp.so need a symbol (fork1) from libjvm which it only gets if the jvm is loaded
664 : // witd RTLD_GLOBAL. On Solaris libjdwp.so is correctly linked with libjvm.so
665 14 : osl::Module moduleRt;
666 : #if defined(LINUX)
667 7 : if (!moduleRt.load(sRuntimeLib, SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_NOW))
668 : #else
669 : #if defined(WNT)
670 : do_msvcr_magic(sRuntimeLib.pData);
671 : #endif
672 : if (!moduleRt.load(sRuntimeLib, SAL_LOADMODULE_DEFAULT))
673 : #endif
674 : {
675 : JFW_ENSURE(false,
676 : "[Java framework]sunjavaplugin" SAL_DLLEXTENSION
677 : " could not load Java runtime library: \n"
678 : + sRuntimeLib + "\n");
679 : JFW_TRACE0("Could not load Java runtime library: " << sRuntimeLib);
680 0 : return JFW_PLUGIN_E_VM_CREATION_FAILED;
681 : }
682 :
683 : #if defined UNX && !defined MACOSX
684 : //Setting the JAVA_HOME is needed for awt
685 14 : OUString sPathLocation;
686 7 : osl_getSystemPathFromFileURL(pInfo->sLocation, & sPathLocation.pData);
687 7 : osl_setEnvironment(OUString("JAVA_HOME").pData, sPathLocation.pData);
688 : #endif
689 :
690 : typedef jint JNICALL JNI_CreateVM_Type(JavaVM **, JNIEnv **, void *);
691 14 : OUString sSymbolCreateJava("JNI_CreateJavaVM");
692 :
693 : JNI_CreateVM_Type * pCreateJavaVM =
694 7 : reinterpret_cast<JNI_CreateVM_Type *>(moduleRt.getFunctionSymbol(sSymbolCreateJava));
695 7 : if (!pCreateJavaVM)
696 : {
697 : OSL_ASSERT(false);
698 : OString sLib = OUStringToOString(
699 0 : sRuntimeLib, osl_getThreadTextEncoding());
700 : OString sSymbol = OUStringToOString(
701 0 : sSymbolCreateJava, osl_getThreadTextEncoding());
702 : fprintf(stderr,"[Java framework]sunjavaplugin" SAL_DLLEXTENSION
703 : "Java runtime library: %s does not export symbol %s !\n",
704 0 : sLib.getStr(), sSymbol.getStr());
705 0 : return JFW_PLUGIN_E_VM_CREATION_FAILED;
706 : }
707 7 : moduleRt.release();
708 :
709 : // Valgrind typically emits many false errors when executing JIT'ed JVM
710 : // code, so force the JVM into interpreted mode:
711 7 : bool addForceInterpreted = FORCE_INTERPRETED > 0;
712 :
713 : // Some testing with Java 1.4 showed that JavaVMOption.optionString has to
714 : // be encoded with the system encoding (i.e., osl_getThreadTextEncoding):
715 : JavaVMInitArgs vm_args;
716 :
717 189 : struct Option {
718 33 : Option(OString const & theOptionString, void * theExtraInfo):
719 33 : optionString(theOptionString), extraInfo(theExtraInfo)
720 33 : {}
721 :
722 : OString optionString;
723 : void * extraInfo;
724 : };
725 14 : std::vector<Option> options;
726 :
727 : // We set an abort handler which is called when the VM calls _exit during
728 : // JNI_CreateJavaVM. This happens when the LD_LIBRARY_PATH does not contain
729 : // all some directories of the Java installation. This is necessary for
730 : // all versions below 1.5.1
731 7 : options.push_back(Option("abort", reinterpret_cast<void*>(abort_handler)));
732 7 : bool hasStackSize = false;
733 33 : for (int i = 0; i < cOptions; i++)
734 : {
735 26 : OString opt(arOptions[i].optionString);
736 : #ifdef UNX
737 : // Until java 1.5 we need to put a plugin.jar or javaplugin.jar (<1.4.2)
738 : // in the class path in order to have applet support:
739 26 : if (opt.startsWith("-Djava.class.path="))
740 : {
741 3 : OString sAddPath = getPluginJarPath(pInfo->sVendor, pInfo->sLocation,pInfo->sVersion);
742 3 : if (!sAddPath.isEmpty())
743 3 : opt += OString(SAL_PATHSEPARATOR) + sAddPath;
744 : }
745 : #endif
746 26 : if (opt == "-Xint") {
747 0 : addForceInterpreted = false;
748 : }
749 26 : if (opt.startsWith("-Xss")) {
750 0 : hasStackSize = true;
751 : }
752 26 : options.push_back(Option(opt, arOptions[i].extraInfo));
753 26 : }
754 7 : if (addForceInterpreted) {
755 0 : options.push_back(Option("-Xint", nullptr));
756 : }
757 7 : if (!hasStackSize) {
758 : #if defined LINUX && defined X86
759 : // At least OpenJDK 1.8.0's os::workaround_expand_exec_shield_cs_limit
760 : // (hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp) can mmap an rwx
761 : // page into the area that the main stack can grow down to according to
762 : // "ulimit -s", as os::init_2's (hotspot/src/os/linux/vm/os_linux.cpp)
763 : // call to
764 : //
765 : // Linux::capture_initial_stack(JavaThread::stack_size_at_create());
766 : //
767 : // caps _initial_thread_stack_size at threadStackSizeInBytes ,i.e.,
768 : // -Xss, which appears to default to only 327680, whereas "ulimit -s"
769 : // defaults to 8192 * 1024 at least on Fedora 20; so attempt to pass in
770 : // a useful -Xss argument:
771 : rlimit l;
772 : if (getrlimit(RLIMIT_STACK, &l) == 0) {
773 : if (l.rlim_cur == RLIM_INFINITY) {
774 : SAL_INFO("jfw", "RLIMIT_STACK RLIM_INFINITY -> 8192K");
775 : l.rlim_cur = 8192 * 1024;
776 : } else if (l.rlim_cur > 512 * 1024 * 1024) {
777 : SAL_INFO(
778 : "jfw", "huge RLIMIT_STACK " << l.rlim_cur << " -> 8192K");
779 : l.rlim_cur = 8192 * 1024;
780 : }
781 : options.push_back(
782 : Option("-Xss" + OString::number(l.rlim_cur), nullptr));
783 : } else {
784 : int e = errno;
785 : SAL_WARN("jfw", "getrlimit(RLIMIT_STACK) failed with errno " << e);
786 : }
787 : #endif
788 : }
789 :
790 14 : boost::scoped_array<JavaVMOption> sarOptions(new JavaVMOption[options.size()]);
791 40 : for (std::vector<Option>::size_type i = 0; i != options.size(); ++i) {
792 : SAL_INFO(
793 : "jfw",
794 : "VM option \"" << options[i].optionString << "\" "
795 : << options[i].extraInfo);
796 33 : sarOptions[i].optionString = const_cast<char *>(
797 33 : options[i].optionString.getStr());
798 33 : sarOptions[i].extraInfo = options[i].extraInfo;
799 : }
800 :
801 : #ifdef MACOSX
802 : vm_args.version= JNI_VERSION_1_4; // issue 88987
803 : #else
804 7 : vm_args.version= JNI_VERSION_1_2;
805 : #endif
806 7 : vm_args.options= sarOptions.get();
807 7 : vm_args.nOptions= options.size(); //TODO overflow
808 7 : vm_args.ignoreUnrecognized= JNI_TRUE;
809 :
810 : /* We set a global flag which is used by the abort handler in order to
811 : determine whether it is should use longjmp to get back into this function.
812 : That is, the abort handler determines if it is on the same stack as this function
813 : and then jumps back into this function.
814 : */
815 7 : g_bInGetJavaVM = 1;
816 : jint err;
817 7 : JavaVM * pJavaVM = 0;
818 7 : memset( jmp_jvm_abort, 0, sizeof(jmp_jvm_abort));
819 7 : int jmpval= setjmp( jmp_jvm_abort );
820 : /* If jmpval is not "0" then this point was reached by a longjmp in the
821 : abort_handler, which was called indirectly by JNI_CreateVM.
822 : */
823 7 : if( jmpval == 0)
824 : {
825 : //returns negative number on failure
826 7 : err= pCreateJavaVM(&pJavaVM, ppEnv, &vm_args);
827 7 : g_bInGetJavaVM = 0;
828 : }
829 : else
830 : // set err to a positive number, so as or recognize that an abort (longjmp)
831 : //occurred
832 0 : err= 1;
833 :
834 7 : if(err != 0)
835 : {
836 0 : if( err < 0)
837 : {
838 : fprintf(stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
839 0 : "Can not create Java Virtual Machine\n");
840 0 : errorcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
841 : }
842 0 : else if( err > 0)
843 : {
844 : fprintf(stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
845 0 : "Can not create JavaVirtualMachine, abort handler was called.\n");
846 0 : errorcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
847 : }
848 : }
849 : else
850 : {
851 7 : *ppVm = pJavaVM;
852 : JFW_TRACE2("JVM created");
853 : }
854 : #else
855 : (void) arOptions;
856 : (void) cOptions;
857 : // On Android we always have a Java VM as we only expect this code
858 : // to be run in an Android app anyway.
859 : *ppVm = lo_get_javavm();
860 : fprintf(stderr, "lo_get_javavm returns %p", *ppVm);
861 : #endif
862 :
863 14 : return errorcode;
864 : }
865 :
866 70 : javaPluginError jfw_plugin_existJRE(const JavaInfo *pInfo, sal_Bool *exist)
867 : {
868 70 : javaPluginError ret = JFW_PLUGIN_E_NONE;
869 70 : if (!pInfo || !exist)
870 0 : return JFW_PLUGIN_E_INVALID_ARG;
871 70 : OUString sLocation(pInfo->sLocation);
872 :
873 70 : if (sLocation.isEmpty())
874 0 : return JFW_PLUGIN_E_INVALID_ARG;
875 140 : ::osl::DirectoryItem item;
876 70 : ::osl::File::RC rc_item = ::osl::DirectoryItem::get(sLocation, item);
877 70 : if (::osl::File::E_None == rc_item)
878 : {
879 70 : *exist = sal_True;
880 : }
881 0 : else if (::osl::File::E_NOENT == rc_item)
882 : {
883 0 : *exist = sal_False;
884 : }
885 : else
886 : {
887 0 : ret = JFW_PLUGIN_E_ERROR;
888 : }
889 : //We can have the situation that the JavaVM runtime library is not
890 : //contained within JAVA_HOME. Then the check for JAVA_HOME would return
891 : //true although the runtime library may not be loadable.
892 : //Or the JAVA_HOME directory of a deinstalled JRE left behind.
893 70 : if (ret == JFW_PLUGIN_E_NONE && *exist == sal_True)
894 : {
895 70 : OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
896 : JFW_TRACE2("Checking existence of Java runtime library");
897 :
898 140 : ::osl::DirectoryItem itemRt;
899 70 : ::osl::File::RC rc_itemRt = ::osl::DirectoryItem::get(sRuntimeLib, itemRt);
900 70 : if (::osl::File::E_None == rc_itemRt)
901 : {
902 70 : *exist = sal_True;
903 : JFW_TRACE2("Java runtime library exist: " << sRuntimeLib);
904 :
905 : }
906 0 : else if (::osl::File::E_NOENT == rc_itemRt)
907 : {
908 0 : *exist = sal_False;
909 : JFW_TRACE2("Java runtime library does not exist: " << sRuntimeLib);
910 : }
911 : else
912 : {
913 0 : ret = JFW_PLUGIN_E_ERROR;
914 : JFW_TRACE2("Error while looking for Java runtime library: " << sRuntimeLib);
915 70 : }
916 : }
917 140 : return ret;
918 : }
919 :
920 :
921 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|