Skip to content

Commit

Permalink
Support files opened via Files#newBufferedWriter (#161)
Browse files Browse the repository at this point in the history
Co-authored-by: Basil Crow <[email protected]>
  • Loading branch information
adangel and basil authored Feb 29, 2024
1 parent 000d9da commit 91e3597
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 0 deletions.
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@
<artifactId>args4j</artifactId>
<version>2.33</version>
</dependency>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/org/kohsuke/file_leak_detector/AgentMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
Expand Down Expand Up @@ -146,6 +147,7 @@ public void run() {
Files.class);

addIfFound(classes, "sun.nio.ch.SocketChannelImpl");
addIfFound(classes, "sun.nio.ch.FileChannelImpl");
addIfFound(classes, "java.net.AbstractPlainSocketImpl");
addIfFound(classes, "java.net.PlainSocketImpl");
addIfFound(classes, "sun.nio.fs.UnixDirectoryStream");
Expand Down Expand Up @@ -370,6 +372,25 @@ static List<ClassTransformSpec> createSpec() {
"(Ljava/nio/channels/spi/SelectorProvider;Ljava/io/FileDescriptor;Ljava/net/InetSocketAddress;)V"),
new OpenSocketInterceptor("<init>", "(Ljava/nio/channels/spi/SelectorProvider;)V"),
new CloseInterceptor("kill")));
spec.add(new ClassTransformSpec(
"sun/nio/ch/FileChannelImpl",
new ReturnFromStaticMethodInterceptor(
"open",
"(Ljava/io/FileDescriptor;Ljava/lang/String;ZZZLjava/io/Closeable;)Ljava/nio/channels/FileChannel;",
4,
"openFileString",
Object.class,
FileDescriptor.class,
String.class),
// this is for java 11/17 - which use Object instead of Closeable as the last parameter
new ReturnFromStaticMethodInterceptor(
"open",
"(Ljava/io/FileDescriptor;Ljava/lang/String;ZZZLjava/lang/Object;)Ljava/nio/channels/FileChannel;",
4,
"openFileString",
Object.class,
FileDescriptor.class,
String.class)));
return spec;
}

Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/kohsuke/file_leak_detector/Listener.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.kohsuke.file_leak_detector;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
Expand All @@ -21,6 +23,7 @@
import java.nio.charset.Charset;
import java.nio.file.DirectoryStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -343,6 +346,15 @@ public static synchronized void open(Object _this, Path p) {
}
}

@SuppressFBWarnings(
value = "PATH_TRAVERSAL_IN",
justification = "path comes from sun.nio.fs.UnixChannelFactory.newFileChannel(int, sun.nio.fs.UnixPath, "
+ "java.lang.String, java.util.Set<? extends java.nio.file.OpenOption>, int). At this point, the path "
+ "is not controlled by the user.")
public static synchronized void openFileString(Object _this, FileDescriptor fileDescriptor, String path) {
open(_this, Paths.get(path));
}

/**
* Called when a pipe is opened, e.g. via SelectorProvider
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
Expand Down Expand Up @@ -135,6 +137,34 @@ public void openCloseFile() throws Exception {
assertThat(traceOutput, containsString("Closed " + tempFile));
}

@Test
public void openCloseFilesBufferedWriter() throws Exception {
try (BufferedWriter writer = Files.newBufferedWriter(tempFile.toPath())) {
assertNotNull(writer);
assertNotNull("No file record for file=" + tempFile + " found", findPathRecord(tempFile.toPath()));
assertThat("Did not have the expected type of 'marker' object: " + obj, obj, instanceOf(FileChannel.class));
}
assertNull("File record for file=" + tempFile + " not removed", findPathRecord(tempFile.toPath()));

String traceOutput = output.toString();
assertThat(traceOutput, containsString("Opened " + tempFile));
assertThat(traceOutput, containsString("Closed " + tempFile));
}

@Test
public void openCloseFilesBufferedReader() throws Exception {
try (BufferedReader reader = Files.newBufferedReader(tempFile.toPath())) {
assertNotNull(reader);
assertNotNull("No file record for file=" + tempFile + " found", findPathRecord(tempFile.toPath()));
assertThat("Did not have the expected type of 'marker' object: " + obj, obj, instanceOf(FileChannel.class));
}
assertNull("File record for file=" + tempFile + " not removed", findPathRecord(tempFile.toPath()));

String traceOutput = output.toString();
assertThat(traceOutput, containsString("Opened " + tempFile));
assertThat(traceOutput, containsString("Closed " + tempFile));
}

@Test
public void openCloseFileChannel() throws Exception {
try (FileChannel fileChannel = FileChannel.open(tempFile.toPath(), StandardOpenOption.APPEND)) {
Expand Down

0 comments on commit 91e3597

Please sign in to comment.