< prev index next >

test/hotspot/jtreg/runtime/8176717/TestInheritFD.java

8205054: Could not find "lsof" on test machine
Reviewed-by: goetz, dholmes

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     }
< prev index next >