Skip to content

Commit

Permalink
Add support for Files.newDirectoryStream, closes jenkinsci#35
Browse files Browse the repository at this point in the history
  • Loading branch information
centic9 committed Jan 3, 2020
1 parent 4d847e8 commit 4c37147
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 2 deletions.
25 changes: 23 additions & 2 deletions src/main/java/org/kohsuke/file_leak_detector/AgentMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.nio.channels.spi.AbstractInterruptibleChannel;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.AbstractSelector;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
Expand Down Expand Up @@ -150,6 +151,8 @@ public void run() {

addIfFound(classes, "sun/nio/ch/SocketChannelImpl");
addIfFound(classes, "java/net/AbstractPlainSocketImpl");
addIfFound(classes, "sun/nio/fs/UnixDirectoryStream");
addIfFound(classes, "sun/nio/fs/UnixSecureDirectoryStream");

instrumentation.retransformClasses(classes.toArray(new Class[0]));

Expand Down Expand Up @@ -243,11 +246,21 @@ static List<ClassTransformSpec> createSpec() {
new ReturnFromStaticMethodInterceptor("open",
"(Ljava/nio/file/Path;Ljava/util/Set;[Ljava/nio/file/attribute/FileAttribute;)Ljava/nio/channels/FileChannel;", 4, "open_filechannel", FileChannel.class, Path.class)),
/*
SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs)
* Detect instances opened via static methods in class java.nio.file.Files
*/
new ClassTransformSpec(Files.class,
// SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs)
new ReturnFromStaticMethodInterceptor("newByteChannel",
"(Ljava/nio/file/Path;Ljava/util/Set;[Ljava/nio/file/attribute/FileAttribute;)Ljava/nio/channels/SeekableByteChannel;", 4, "open_filechannel", SeekableByteChannel.class, Path.class)),
"(Ljava/nio/file/Path;Ljava/util/Set;[Ljava/nio/file/attribute/FileAttribute;)Ljava/nio/channels/SeekableByteChannel;", 4, "open_filechannel", SeekableByteChannel.class, Path.class),
// DirectoryStream<Path> newDirectoryStream(Path dir)
new ReturnFromStaticMethodInterceptor("newDirectoryStream",
"(Ljava/nio/file/Path;)Ljava/nio/file/DirectoryStream;", 2, "open_directorystream", DirectoryStream.class, Path.class),
// DirectoryStream<Path> newDirectoryStream(Path dir, String glob)
new ReturnFromStaticMethodInterceptor("newDirectoryStream",
"(Ljava/nio/file/Path;Ljava/lang/String;)Ljava/nio/file/DirectoryStream;", 6, "open_directorystream", DirectoryStream.class, Path.class),
// DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter)
new ReturnFromStaticMethodInterceptor("newDirectoryStream",
"(Ljava/nio/file/Path;Ljava/nio/file/DirectoryStream$Filter;)Ljava/nio/file/DirectoryStream;", 3, "open_directorystream", DirectoryStream.class, Path.class)),
/*
* Detect new Pipes
*/
Expand All @@ -258,6 +271,14 @@ SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options,
*/
new ClassTransformSpec(AbstractInterruptibleChannel.class,
new CloseInterceptor("close")),
/*
* We need to see closing of DirectoryStream instances,
* however they are OS-specific, so we need to list them via String-name
*/
new ClassTransformSpec("sun/nio/fs/UnixDirectoryStream",
new CloseInterceptor("close")),
new ClassTransformSpec("sun/nio/fs/UnixSecureDirectoryStream",
new CloseInterceptor("close")),

/**
* Detect selectors, which may open native pipes and anonymous inodes for event polling.
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/kohsuke/file_leak_detector/Listener.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.nio.channels.SeekableByteChannel;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.file.DirectoryStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Date;
Expand Down Expand Up @@ -314,6 +315,10 @@ public static synchronized void open_filechannel(SeekableByteChannel byteChannel
open(byteChannel, path.toFile());
}

public static synchronized void open_directorystream(DirectoryStream<?> directoryStream, Path path) {
open(directoryStream, path.toFile());
}

public static synchronized void openSelector(Object _this) {
if (_this instanceof Selector) {
put(_this, new SelectorRecord((Selector)_this));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
// the following two are not available in all JVMs
seenClasses.remove("sun/nio/ch/SocketChannelImpl");
seenClasses.remove("java/net/AbstractPlainSocketImpl");
seenClasses.remove("sun/nio/fs/UnixDirectoryStream");
seenClasses.remove("sun/nio/fs/UnixSecureDirectoryStream");

assertTrue("Had classes in the spec which were not instrumented: " + seenClasses,
seenClasses.isEmpty());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import java.io.StringWriter;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

import org.junit.After;
Expand Down Expand Up @@ -88,6 +90,75 @@ public void openCloseFilesNewByteChannel() throws Exception {
assertTrue(traceOutput.contains("Closed " + tempFile));
}

@Test
public void openCloseFilesNewDirectoryStream() throws Exception {
assertTrue(tempFile.delete());
assertTrue(tempFile.mkdirs());

DirectoryStream<Path> stream = Files.newDirectoryStream(tempFile.toPath());
assertNotNull("No file record for file=" + tempFile + " found", findFileRecord(tempFile));

stream.close();
assertNull("File record for file=" + tempFile + " not removed", findFileRecord(tempFile));

String traceOutput = output.toString();
assertTrue(traceOutput.contains("Opened " + tempFile));
assertTrue(traceOutput.contains("Closed " + tempFile));
}

@Test
public void openCloseFilesNewDirectoryStreamWithStarGlob() throws Exception {
assertTrue(tempFile.delete());
assertTrue(tempFile.mkdirs());

DirectoryStream<Path> stream = Files.newDirectoryStream(tempFile.toPath(), "*");
assertNotNull("No file record for file=" + tempFile + " found", findFileRecord(tempFile));

stream.close();
assertNull("File record for file=" + tempFile + " not removed", findFileRecord(tempFile));

String traceOutput = output.toString();
assertTrue(traceOutput.contains("Opened " + tempFile));
assertTrue(traceOutput.contains("Closed " + tempFile));
}

@Test
public void openCloseFilesNewDirectoryStreamWithNonStarGlob() throws Exception {
assertTrue(tempFile.delete());
assertTrue(tempFile.mkdirs());

DirectoryStream<Path> stream = Files.newDirectoryStream(tempFile.toPath(), "my*test*glob");
assertNotNull("No file record for file=" + tempFile + " found", findFileRecord(tempFile));

stream.close();
assertNull("File record for file=" + tempFile + " not removed", findFileRecord(tempFile));

String traceOutput = output.toString();
assertTrue(traceOutput.contains("Opened " + tempFile));
assertTrue(traceOutput.contains("Closed " + tempFile));
}

@Test
public void openCloseFilesNewDirectoryStreamWithFilter() throws Exception {
assertTrue(tempFile.delete());
assertTrue(tempFile.mkdirs());

DirectoryStream<Path> stream = Files.newDirectoryStream(tempFile.toPath(), new DirectoryStream.Filter<Path>() {
@Override
public boolean accept(Path entry) {
return true;
}
});
assertNotNull("No file record for file=" + tempFile + " found", findFileRecord(tempFile));

stream.close();
assertNull("File record for file=" + tempFile + " not removed", findFileRecord(tempFile));

String traceOutput = output.toString();
assertTrue(traceOutput.contains("Opened " + tempFile));
assertTrue(traceOutput.contains("Closed " + tempFile));
}

/* This is only available in Java 8 and newer...
@Test
public void openCloseFileLines() throws Exception {
Expand Down

0 comments on commit 4c37147

Please sign in to comment.