LCOV - code coverage report
Current view: top level - jvmfwk/plugins/sunmajor/pluginlib - sunjavaplugin.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 154 263 58.6 %
Date: 2015-06-13 12:38:46 Functions: 12 15 80.0 %
Legend: Lines: hit not hit

          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 &quot;bad&quot; 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: */

Generated by: LCOV version 1.11