8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 */
22
23 import static java.io.File.createTempFile;
24 import static java.lang.Long.parseLong;
25 import static java.lang.System.getProperty;
26 import static java.nio.file.Files.readAllBytes;
27 import static java.util.Arrays.stream;
28 import static java.util.Collections.emptyList;
29 import static java.util.stream.Collectors.joining;
30 import static java.util.stream.Collectors.toList;
31 import static jdk.test.lib.process.ProcessTools.createJavaProcessBuilder;
32
33 import java.io.BufferedReader;
34 import java.io.File;
35 import java.io.FileNotFoundException;
36 import java.io.FileOutputStream;
37 import java.io.IOException;
38 import java.io.InputStreamReader;
39 import java.util.Collection;
40 import java.util.Optional;
41 import java.util.stream.Stream;
42
43 /*
44 * @test TestInheritFD
45 * @bug 8176717 8176809
46 * @summary a new process should not inherit open file descriptors
47 * @library /test/lib
|
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 */
22
23 import static java.io.File.createTempFile;
24 import static java.lang.Long.parseLong;
25 import static java.lang.System.getProperty;
26 import static java.nio.file.Files.readAllBytes;
27 import static java.util.Arrays.stream;
28 import static java.util.stream.Collectors.joining;
29 import static java.util.stream.Collectors.toList;
30 import static jdk.test.lib.process.ProcessTools.createJavaProcessBuilder;
31
32 import java.io.BufferedReader;
33 import java.io.File;
34 import java.io.FileNotFoundException;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStreamReader;
38 import java.util.Collection;
39 import java.util.Optional;
40 import java.util.stream.Stream;
41
42 /*
43 * @test TestInheritFD
44 * @bug 8176717 8176809
45 * @summary a new process should not inherit open file descriptors
46 * @library /test/lib
|
62 * (windows can not rename opened files easily)
63 *
64 * The third VM communicates the success to rename the file by printing "CLOSED
65 * FD". The first VM checks that the string was printed by the third VM.
66 *
67 * On unix like systems "lsof" or "pfiles" is used.
68 */
69
70 public class TestInheritFD {
71
72 public static final String LEAKS_FD = "VM RESULT => LEAKS FD";
73 public static final String RETAINS_FD = "VM RESULT => RETAINS FD";
74 public static final String EXIT = "VM RESULT => VM EXIT";
75 public static final String LOG_SUFFIX = ".strangelogsuffixthatcanbecheckedfor";
76
77 // first VM
78 public static void main(String[] args) throws Exception {
79 String logPath = createTempFile("logging", LOG_SUFFIX).getName();
80 File commFile = createTempFile("communication", ".txt");
81
82 ProcessBuilder pb = createJavaProcessBuilder(
83 "-Xlog:gc:\"" + logPath + "\"",
84 "-Dtest.jdk=" + getProperty("test.jdk"),
85 VMStartedWithLogging.class.getName(),
86 logPath);
87
88 pb.redirectOutput(commFile); // use temp file to communicate between processes
89 pb.start();
90
91 String out = "";
92 do {
93 out = new String(readAllBytes(commFile.toPath()));
94 Thread.sleep(100);
95 System.out.println("SLEEP 100 millis");
96 } while (!out.contains(EXIT));
97
98 System.out.println(out);
99 if (out.contains(RETAINS_FD)) {
100 System.out.println("Log file was not inherited by third VM");
101 } else {
102 throw new RuntimeException("could not match: " + RETAINS_FD);
103 }
104 }
105
106 static class VMStartedWithLogging {
107 // second VM
108 public static void main(String[] args) throws IOException, InterruptedException {
109 ProcessBuilder pb = createJavaProcessBuilder(
110 "-Dtest.jdk=" + getProperty("test.jdk"),
111 VMShouldNotInheritFileDescriptors.class.getName(),
112 args[0],
113 "" + ProcessHandle.current().pid());
114 pb.inheritIO(); // in future, redirect information from third VM to first VM
115 pb.start();
116
117 if (getProperty("os.name").toLowerCase().contains("win") == false) {
118 System.out.println("(Second VM) Open file descriptors:\n" + outputContainingFilenames().stream().collect(jo
119 }
120 }
121 }
122
123 static class VMShouldNotInheritFileDescriptors {
124 // third VM
125 public static void main(String[] args) throws InterruptedException {
126 try {
127 File logFile = new File(args[0]);
128 long parentPid = parseLong(args[1]);
129 fakeLeakyJVM(false); // for debugging of test case
130
131 if (getProperty("os.name").toLowerCase().contains("win")) {
132 windows(logFile, parentPid);
133 } else {
134 Collection<String> output = outputContainingFilenames();
135 System.out.println("(Third VM) Open file descriptors:\n" + output.stream().collect(joining("\n")));
136 System.out.println(findOpenLogFile(output) ? LEAKS_FD : RETAINS_FD);
137 }
138 } catch (Exception e) {
139 System.out.println(e.toString());
140 } finally {
141 System.out.println(EXIT);
142 }
143 }
144 }
145
146 // for debugging of test case
147 @SuppressWarnings("resource")
148 static void fakeLeakyJVM(boolean fake) {
149 if (fake) {
150 try {
151 new FileOutputStream("fakeLeakyJVM" + LOG_SUFFIX, false);
152 } catch (FileNotFoundException e) {
153 }
154 }
155 }
156
157 static Stream<String> run(String... args){
158 try {
159 return new BufferedReader(new InputStreamReader(new ProcessBuilder(args).start().getInputStream())).lines();
160 } catch (IOException e) {
161 throw new RuntimeException(e);
162 }
163 }
164
165 static Collection<String> outputContainingFilenames() {
166 long pid = ProcessHandle.current().pid();
167 Optional<String[]> command = stream(new String[][]{
168 {"/usr/bin/lsof", "-p"},
169 {"/usr/sbin/lsof", "-p"},
170 {"/bin/lsof", "-p"},
171 {"/sbin/lsof", "-p"},
172 {"/usr/local/bin/lsof", "-p"},
173 {"/usr/bin/pfiles", "-F"}}) // Solaris
174 .filter(args -> new File(args[0]).exists())
175 .findFirst();
176
177 System.out.println("using command: " + command.map((c) -> c[0] + " " + c[1]).orElse("<not found>"));
178 // if command can not be found return list without log file (some machines does not have "lsof" in the expected pla
179 return command.map(c -> run(c[0], c[1], "" + pid).collect(toList())).orElse(emptyList());
180 }
181
182 static boolean findOpenLogFile(Collection<String> fileNames) {
183 return fileNames.stream()
184 .filter(fileName -> fileName.contains(LOG_SUFFIX))
185 .findAny()
186 .isPresent();
187 }
188
189 static void windows(File f, long parentPid) throws InterruptedException {
190 System.out.println("waiting for pid: " + parentPid);
191 ProcessHandle.of(parentPid).ifPresent(handle -> handle.onExit().join());
192 System.out.println("trying to rename file to the same name: " + f);
193 System.out.println(f.renameTo(f) ? RETAINS_FD : LEAKS_FD); // this parts communicates a closed file descriptor by p
194 }
|
61 * (windows can not rename opened files easily)
62 *
63 * The third VM communicates the success to rename the file by printing "CLOSED
64 * FD". The first VM checks that the string was printed by the third VM.
65 *
66 * On unix like systems "lsof" or "pfiles" is used.
67 */
68
69 public class TestInheritFD {
70
71 public static final String LEAKS_FD = "VM RESULT => LEAKS FD";
72 public static final String RETAINS_FD = "VM RESULT => RETAINS FD";
73 public static final String EXIT = "VM RESULT => VM EXIT";
74 public static final String LOG_SUFFIX = ".strangelogsuffixthatcanbecheckedfor";
75
76 // first VM
77 public static void main(String[] args) throws Exception {
78 String logPath = createTempFile("logging", LOG_SUFFIX).getName();
79 File commFile = createTempFile("communication", ".txt");
80
81 if (isWindows() == false && lsofCommand().isPresent() == false) {
82 System.out.println("Could not find lsof like command");
83 System.out.println("Exit test case as successful though it could not verify anything");
84 return;
85 }
86
87 ProcessBuilder pb = createJavaProcessBuilder(
88 "-Xlog:gc:\"" + logPath + "\"",
89 "-Dtest.jdk=" + getProperty("test.jdk"),
90 VMStartedWithLogging.class.getName(),
91 logPath);
92
93 pb.redirectOutput(commFile); // use temp file to communicate between processes
94 pb.start();
95
96 String out = "";
97 do {
98 out = new String(readAllBytes(commFile.toPath()));
99 Thread.sleep(100);
100 System.out.println("SLEEP 100 millis");
101 } while (!out.contains(EXIT));
102
103 System.out.println(out);
104 if (out.contains(RETAINS_FD)) {
105 System.out.println("Log file was not inherited by third VM");
106 } else {
107 throw new RuntimeException("could not match: " + RETAINS_FD);
108 }
109 }
110
111 static class VMStartedWithLogging {
112 // second VM
113 public static void main(String[] args) throws IOException, InterruptedException {
114 ProcessBuilder pb = createJavaProcessBuilder(
115 "-Dtest.jdk=" + getProperty("test.jdk"),
116 VMShouldNotInheritFileDescriptors.class.getName(),
117 args[0],
118 "" + ProcessHandle.current().pid());
119 pb.inheritIO(); // in future, redirect information from third VM to first VM
120 pb.start();
121
122 if (!isWindows()) {
123 System.out.println("(Second VM) Open file descriptors:\n" + outputContainingFilenames().stream().collect(jo
124 }
125 }
126 }
127
128 static class VMShouldNotInheritFileDescriptors {
129 // third VM
130 public static void main(String[] args) throws InterruptedException {
131 try {
132 File logFile = new File(args[0]);
133 long parentPid = parseLong(args[1]);
134 fakeLeakyJVM(false); // for debugging of test case
135
136 if (isWindows()) {
137 windows(logFile, parentPid);
138 } else {
139 Collection<String> output = outputContainingFilenames();
140 System.out.println("(Third VM) Open file descriptors:\n" + output.stream().collect(joining("\n")));
141 System.out.println(findOpenLogFile(output) ? LEAKS_FD : RETAINS_FD);
142 }
143 } catch (Exception e) {
144 System.out.println(e.toString());
145 } finally {
146 System.out.println(EXIT);
147 }
148 }
149 }
150
151 // for debugging of test case
152 @SuppressWarnings("resource")
153 static void fakeLeakyJVM(boolean fake) {
154 if (fake) {
155 try {
156 new FileOutputStream("fakeLeakyJVM" + LOG_SUFFIX, false);
157 } catch (FileNotFoundException e) {
158 }
159 }
160 }
161
162 static Stream<String> run(String... args){
163 try {
164 return new BufferedReader(new InputStreamReader(new ProcessBuilder(args).start().getInputStream())).lines();
165 } catch (IOException e) {
166 throw new RuntimeException(e);
167 }
168 }
169
170 static boolean isWindows() {
171 return getProperty("os.name").toLowerCase().contains("win");
172 }
173
174 static Optional<String[]> lsofCommand() {
175 return stream(new String[][]{
176 {"/usr/bin/lsof", "-p"},
177 {"/usr/sbin/lsof", "-p"},
178 {"/bin/lsof", "-p"},
179 {"/sbin/lsof", "-p"},
180 {"/usr/local/bin/lsof", "-p"},
181 {"/usr/bin/pfiles", "-F"}}) // Solaris
182 .filter(args -> new File(args[0]).exists())
183 .findFirst();
184 }
185
186 static Collection<String> outputContainingFilenames() {
187 long pid = ProcessHandle.current().pid();
188
189 String[] command = lsofCommand().orElseThrow(() -> new RuntimeException("lsof like command not found"));
190 System.out.println("using command: " + command[0] + " " + command[1]);
191 return run(command[0], command[1], "" + pid).collect(toList());
192 }
193
194 static boolean findOpenLogFile(Collection<String> fileNames) {
195 return fileNames.stream()
196 .filter(fileName -> fileName.contains(LOG_SUFFIX))
197 .findAny()
198 .isPresent();
199 }
200
201 static void windows(File f, long parentPid) throws InterruptedException {
202 System.out.println("waiting for pid: " + parentPid);
203 ProcessHandle.of(parentPid).ifPresent(handle -> handle.onExit().join());
204 System.out.println("trying to rename file to the same name: " + f);
205 System.out.println(f.renameTo(f) ? RETAINS_FD : LEAKS_FD); // this parts communicates a closed file descriptor by p
206 }
|