1 /*
2  * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 4780570 4731671 6354700 6367077 6670965 4882974
27  * @summary Checks for LD_LIBRARY_PATH and execution  on *nixes
28  * @modules jdk.compiler
29  *          jdk.zipfs
30  * @compile -XDignore.symbol.file ExecutionEnvironment.java
31  * @run main/othervm ExecutionEnvironment
32  */
33 
34 /*
35  * This tests for various things as follows:
36  * Ensures that:
37  *   1. uneccessary execs do not occur
38  *   2. the environment is pristine,  users environment variable wrt.
39  *      LD_LIBRARY_PATH if set are not modified in any way.
40  *   3. the correct vm is chosen with -server and -client options
41  *   4. the VM on Solaris correctly interprets the LD_LIBRARY_PATH32
42  *      and LD_LIBRARY_PATH64 variables if set by the user, ie.
43  *      i. on 32 bit systems:
44  *         a. if LD_LIBRARY_PATH32 is set it will override LD_LIBRARY_PATH
45  *         b. LD_LIBRARY_PATH64 is ignored if set
46  *      ii. on 64 bit systems:
47  *            a. if LD_LIBRARY_PATH64 is set it will override LD_LIBRARY_PATH
48  *            b. LD_LIBRARY_PATH32 is ignored if set
49  *   5. no extra symlink exists on Solaris ie.
50  *      lib/$arch/libjvm.so -> client/libjvm.so
51  * TODO:
52  *      a. perhaps we need to add a test to audit all environment variables are
53  *         in pristine condition after the launch, there may be a few that the
54  *         launcher may add as implementation details.
55  *      b. add a pldd for solaris to ensure only one libjvm.so is linked
56  */
57 import java.io.File;
58 import java.io.FileNotFoundException;
59 import java.util.ArrayList;
60 import java.util.HashMap;
61 import java.util.List;
62 import java.util.Map;
63 
64 public class ExecutionEnvironment extends TestHelper {
65     static final String LD_LIBRARY_PATH    = TestHelper.isMacOSX
66             ? "DYLD_LIBRARY_PATH"
67             : TestHelper.isAIX
68                     ? "LIBPATH"
69                     : "LD_LIBRARY_PATH";
70     static final String LD_LIBRARY_PATH_32 = LD_LIBRARY_PATH + "_32";
71     static final String LD_LIBRARY_PATH_64 = LD_LIBRARY_PATH + "_64";
72 
73     // Note: these paths need not exist on the filesytem
74     static final String LD_LIBRARY_PATH_VALUE    = "/Bridge/On/The/River/Kwai";
75     static final String LD_LIBRARY_PATH_32_VALUE = "/Lawrence/Of/Arabia";
76     static final String LD_LIBRARY_PATH_64_VALUE = "/A/Passage/To/India";
77 
78     static final String[] LD_PATH_STRINGS = {
79         LD_LIBRARY_PATH + "=" + LD_LIBRARY_PATH_VALUE,
80         LD_LIBRARY_PATH_32 + "=" + LD_LIBRARY_PATH_32_VALUE,
81         LD_LIBRARY_PATH_64 + "=" + LD_LIBRARY_PATH_64_VALUE
82     };
83 
84     static final File testJarFile = new File("EcoFriendly.jar");
85 
ExecutionEnvironment()86     public ExecutionEnvironment() {
87         createTestJar();
88     }
89 
createTestJar()90     static void createTestJar() {
91         try {
92             List<String> codeList = new ArrayList<>();
93             codeList.add("static void printValue(String name, boolean property) {\n");
94             codeList.add("    String value = (property) ? System.getProperty(name) : System.getenv(name);\n");
95             codeList.add("    System.out.println(name + \"=\" + value);\n");
96             codeList.add("}\n");
97             codeList.add("public static void main(String... args) {\n");
98             codeList.add("    System.out.println(\"Execute test:\");\n");
99             codeList.add("    printValue(\"os.name\", true);\n");
100             codeList.add("    printValue(\"os.arch\", true);\n");
101             codeList.add("    printValue(\"os.version\", true);\n");
102             codeList.add("    printValue(\"sun.arch.data.model\", true);\n");
103             codeList.add("    printValue(\"java.library.path\", true);\n");
104             codeList.add("    printValue(\"" + LD_LIBRARY_PATH + "\", false);\n");
105             codeList.add("    printValue(\"" + LD_LIBRARY_PATH_32 + "\", false);\n");
106             codeList.add("    printValue(\"" + LD_LIBRARY_PATH_64 + "\", false);\n");
107             codeList.add("}\n");
108             String[] clist = new String[codeList.size()];
109             createJar(testJarFile, codeList.toArray(clist));
110         } catch (FileNotFoundException fnfe) {
111             throw new RuntimeException(fnfe);
112         }
113     }
flagError(TestResult tr, String message)114     private void flagError(TestResult tr, String message) {
115         System.err.println(tr);
116         throw new RuntimeException(message);
117     }
118     /*
119      * tests if the launcher pollutes the LD_LIBRARY_PATH variables ie. there
120      * should not be any new variables or pollution/mutations of any kind, the
121      * environment should be pristine.
122      */
123     @Test
testEcoFriendly()124     void testEcoFriendly() {
125         Map<String, String> env = new HashMap<>();
126         for (String x : LD_PATH_STRINGS) {
127             String pairs[] = x.split("=");
128             env.put(pairs[0], pairs[1]);
129         }
130 
131         TestResult tr =
132             doExec(env, javaCmd, "-jar", testJarFile.getAbsolutePath());
133 
134         if (!tr.isNotZeroOutput()) {
135             flagError(tr, "Error: No output at all. Did the test execute ?");
136         }
137 
138         for (String x : LD_PATH_STRINGS) {
139             if (!tr.contains(x)) {
140                 if (TestHelper.isAIX && x.startsWith(LD_LIBRARY_PATH)) {
141                     // AIX does not support the '-rpath' linker options so the
142                     // launchers have to prepend the jdk library path to 'LIBPATH'.
143                     String aixLibPath = LD_LIBRARY_PATH + "=" +
144                         System.getenv(LD_LIBRARY_PATH) +
145                         System.getProperty("path.separator") + LD_LIBRARY_PATH_VALUE;
146                     if (!tr.matches(aixLibPath)) {
147                         flagError(tr, "FAIL: did not get <" + aixLibPath + ">");
148                     }
149                 }
150                 else {
151                     flagError(tr, "FAIL: did not get <" + x + ">");
152                 }
153             }
154         }
155     }
156 
157     /*
158      * ensures that there are no execs as long as we are in the same
159      * data model
160      */
161     @Test
testNoExec()162     void testNoExec() {
163         Map<String, String> env = new HashMap<>();
164         env.put(JLDEBUG_KEY, "true");
165         TestResult tr = doExec(env, javaCmd, "-version");
166         if (tr.testOutput.contains(EXPECTED_MARKER)) {
167             flagError(tr, "testNoExec: found  warning <" + EXPECTED_MARKER +
168                     "> the process execing ?");
169         }
170     }
171 
172     /*
173      * This test ensures that LD_LIBRARY_PATH* values are interpreted by the VM
174      * and the expected java.library.path behaviour.
175      * For Generic platforms (All *nixes):
176      *    * All LD_LIBRARY_PATH variable should be on java.library.path
177      * For Solaris 32-bit
178      *    * The LD_LIBRARY_PATH_32 should override LD_LIBRARY_PATH if specified
179      * For Solaris 64-bit
180      *    * The LD_LIBRARY_PATH_64 should override LD_LIBRARY_PATH if specified
181      */
182     @Test
testJavaLibraryPath()183     void testJavaLibraryPath() {
184         TestResult tr;
185 
186         Map<String, String> env = new HashMap<>();
187 
188         if (TestHelper.isSolaris) {
189             // no override
190             env.clear();
191             env.put(LD_LIBRARY_PATH, LD_LIBRARY_PATH_VALUE);
192             tr = doExec(env, javaCmd, "-jar", testJarFile.getAbsolutePath());
193             verifyJavaLibraryPathGeneric(tr);
194 
195             env.clear();
196             for (String x : LD_PATH_STRINGS) {
197                 String pairs[] = x.split("=");
198                 env.put(pairs[0], pairs[1]);
199             }
200 
201             // verify the override occurs for 64-bit system
202             tr = doExec(env, javaCmd, "-jar", testJarFile.getAbsolutePath());
203             verifyJavaLibraryPathOverride(tr, false);
204         } else {
205             for (String x : LD_PATH_STRINGS) {
206                 String pairs[] = x.split("=");
207                 env.put(pairs[0], pairs[1]);
208             }
209 
210             tr = doExec(env, javaCmd, "-jar", testJarFile.getAbsolutePath());
211             verifyJavaLibraryPathGeneric(tr);
212         }
213     }
214 
verifyJavaLibraryPathGeneric(TestResult tr)215     private void verifyJavaLibraryPathGeneric(TestResult tr) {
216         if (!tr.matches("java.library.path=.*" + LD_LIBRARY_PATH_VALUE + ".*")) {
217             flagError(tr, "testJavaLibraryPath: java.library.path does not contain " +
218                     LD_LIBRARY_PATH_VALUE);
219         }
220     }
221 
verifyJavaLibraryPathOverride(TestResult tr, boolean is32Bit)222     private void verifyJavaLibraryPathOverride(TestResult tr,
223             boolean is32Bit) {
224         // make sure the 32/64 bit value exists
225         if (!tr.matches("java.library.path=.*" +
226                 (is32Bit ? LD_LIBRARY_PATH_32_VALUE : LD_LIBRARY_PATH_64_VALUE) + ".*")) {
227             flagError(tr, "verifyJavaLibraryPathOverride: " +
228                 " java.library.path does not contain " +
229                     (is32Bit ? LD_LIBRARY_PATH_32_VALUE : LD_LIBRARY_PATH_64_VALUE));
230 
231         }
232         // make sure the generic value is absent
233         if (!tr.notMatches("java.library.path=.*" + LD_LIBRARY_PATH_VALUE + ".*")) {
234             flagError(tr, "verifyJavaLibraryPathOverride: " +
235                     " java.library.path contains " + LD_LIBRARY_PATH_VALUE);
236         }
237     }
238 
239     /*
240      * ensures we have indeed exec'ed the correct vm of choice if it exists
241      */
242     @Test
testVmSelection()243     void testVmSelection() {
244         boolean haveSomeVM = false;
245         if (haveClientVM) {
246             tryVmOption("-client", ".*Client VM.*");
247             haveSomeVM = true;
248         }
249         if (haveServerVM) {
250             tryVmOption("-server", ".*Server VM.*");
251             haveSomeVM = true;
252         }
253         if (!haveSomeVM) {
254             String msg = "Don't have a known VM";
255             System.err.println(msg);
256             throw new RuntimeException(msg);
257         }
258     }
259 
tryVmOption(String opt, String expected)260     private void tryVmOption(String opt, String expected) {
261         TestResult tr = doExec(javaCmd, opt, "-version");
262         if (!tr.matches(expected)) {
263             flagError(tr, "the expected vm " + opt + " did not launch");
264         }
265     }
266 
267     /*
268      * checks to see there is no extra libjvm.so than needed
269      */
270     @Test
testNoSymLink()271     void testNoSymLink() {
272         if (is64Bit) {
273             return;
274         }
275 
276         File symLink = null;
277         String libPathPrefix = "/lib";
278         symLink = new File(JAVAHOME, libPathPrefix +
279                 getJreArch() + "/" + LIBJVM);
280         if (symLink.exists()) {
281             throw new RuntimeException("symlink exists " + symLink.getAbsolutePath());
282         }
283     }
main(String... args)284     public static void main(String... args) throws Exception {
285         if (isWindows) {
286             System.err.println("Warning: test not applicable to windows");
287             return;
288         }
289         ExecutionEnvironment ee = new ExecutionEnvironment();
290         ee.run(args);
291     }
292 }
293