Skip to content

Commit d62e819

Browse files
authored
Degrade gracefully on Java 19+ (#145)
1 parent 11c1d71 commit d62e819

File tree

2 files changed

+45
-42
lines changed

2 files changed

+45
-42
lines changed

src/main/java/org/kohsuke/file_leak_detector/AgentMain.java

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ public void run() {
132132
FileInputStream.class,
133133
FileOutputStream.class,
134134
RandomAccessFile.class,
135-
Class.forName("java.net.PlainSocketImpl"),
136135
ZipFile.class,
137136
AbstractSelectableChannel.class,
138137
AbstractInterruptibleChannel.class,
@@ -142,6 +141,7 @@ public void run() {
142141

143142
addIfFound(classes, "sun.nio.ch.SocketChannelImpl");
144143
addIfFound(classes, "java.net.AbstractPlainSocketImpl");
144+
addIfFound(classes, "java.net.PlainSocketImpl");
145145
addIfFound(classes, "sun.nio.fs.UnixDirectoryStream");
146146
addIfFound(classes, "sun.nio.fs.UnixSecureDirectoryStream");
147147
addIfFound(classes, "sun.nio.fs.WindowsDirectoryStream");
@@ -301,59 +301,59 @@ static List<ClassTransformSpec> createSpec() {
301301
new ClassTransformSpec(
302302
"sun/nio/fs/WindowsDirectoryStream", new CloseInterceptor("close")));
303303
}
304-
Collections.addAll(
305-
spec,
306-
/*
307-
* Detect selectors, which may open native pipes and anonymous inodes for event polling.
308-
*/
309-
new ClassTransformSpec(AbstractSelector.class,
310-
new ConstructorInterceptor("(Ljava/nio/channels/spi/SelectorProvider;)V", "openSelector"),
311-
new CloseInterceptor("close")),
304+
/*
305+
* Detect selectors, which may open native pipes and anonymous inodes for event polling.
306+
*/
307+
spec.add(new ClassTransformSpec(
308+
AbstractSelector.class,
309+
new ConstructorInterceptor("(Ljava/nio/channels/spi/SelectorProvider;)V", "openSelector"),
310+
new CloseInterceptor("close")));
311+
/*
312+
* java.net.Socket/ServerSocket uses SocketImpl, and this is where FileDescriptors are actually managed.
313+
*
314+
* SocketInputStream/SocketOutputStream does not maintain a separate FileDescriptor. They just all piggy back on
315+
* the same SocketImpl instance.
316+
*/
317+
if (Runtime.version().feature() < 19) {
318+
spec.add(new ClassTransformSpec(
319+
"java/net/PlainSocketImpl",
320+
// this is where a new file descriptor is allocated.
321+
// it'll occupy a socket even before it gets connected
322+
new OpenSocketInterceptor("create", "(Z)V"),
312323

313-
/*
314-
java.net.Socket/ServerSocket uses SocketImpl, and this is where FileDescriptors
315-
are actually managed.
324+
// When a socket is accepted, it goes to "accept(SocketImpl s)"
325+
// where 's' is the new socket and 'this' is the server socket
326+
new AcceptInterceptor("accept", "(Ljava/net/SocketImpl;)V"),
316327

317-
SocketInputStream/SocketOutputStream does not maintain a separate FileDescriptor.
318-
They just all piggy back on the same SocketImpl instance.
319-
*/
320-
new ClassTransformSpec("java/net/PlainSocketImpl",
328+
// file descriptor actually get closed in socketClose()
329+
// socketPreClose() appears to do something similar, but if you read the source code
330+
// of the native socketClose0() method, then you see that it actually doesn't close
331+
// a file descriptor.
332+
new CloseInterceptor("socketClose")));
333+
// Later versions of the JDK abstracted out the parts of PlainSocketImpl above into a super class
334+
spec.add(new ClassTransformSpec(
335+
"java/net/AbstractPlainSocketImpl",
321336
// this is where a new file descriptor is allocated.
322337
// it'll occupy a socket even before it gets connected
323338
new OpenSocketInterceptor("create", "(Z)V"),
324339

325340
// When a socket is accepted, it goes to "accept(SocketImpl s)"
326341
// where 's' is the new socket and 'this' is the server socket
327-
new AcceptInterceptor("accept","(Ljava/net/SocketImpl;)V"),
342+
new AcceptInterceptor("accept", "(Ljava/net/SocketImpl;)V"),
328343

329344
// file descriptor actually get closed in socketClose()
330345
// socketPreClose() appears to do something similar, but if you read the source code
331346
// of the native socketClose0() method, then you see that it actually doesn't close
332347
// a file descriptor.
333-
new CloseInterceptor("socketClose")
334-
),
335-
// Later versions of the JDK abstracted out the parts of PlainSocketImpl above into a super class
336-
new ClassTransformSpec("java/net/AbstractPlainSocketImpl",
337-
// this is where a new file descriptor is allocated.
338-
// it'll occupy a socket even before it gets connected
339-
new OpenSocketInterceptor("create", "(Z)V"),
340-
341-
// When a socket is accepted, it goes to "accept(SocketImpl s)"
342-
// where 's' is the new socket and 'this' is the server socket
343-
new AcceptInterceptor("accept","(Ljava/net/SocketImpl;)V"),
344-
345-
// file descriptor actually get closed in socketClose()
346-
// socketPreClose() appears to do something similar, but if you read the source code
347-
// of the native socketClose0() method, then you see that it actually doesn't close
348-
// a file descriptor.
349-
new CloseInterceptor("socketClose")
350-
),
351-
new ClassTransformSpec("sun/nio/ch/SocketChannelImpl",
352-
new OpenSocketInterceptor("<init>", "(Ljava/nio/channels/spi/SelectorProvider;Ljava/io/FileDescriptor;Ljava/net/InetSocketAddress;)V"),
353-
new OpenSocketInterceptor("<init>", "(Ljava/nio/channels/spi/SelectorProvider;)V"),
354-
new CloseInterceptor("kill")
355-
)
356-
);
348+
new CloseInterceptor("socketClose")));
349+
}
350+
spec.add(new ClassTransformSpec(
351+
"sun/nio/ch/SocketChannelImpl",
352+
new OpenSocketInterceptor(
353+
"<init>",
354+
"(Ljava/nio/channels/spi/SelectorProvider;Ljava/io/FileDescriptor;Ljava/net/InetSocketAddress;)V"),
355+
new OpenSocketInterceptor("<init>", "(Ljava/nio/channels/spi/SelectorProvider;)V"),
356+
new CloseInterceptor("kill")));
357357
return spec;
358358
}
359359

src/test/java/org/kohsuke/file_leak_detector/AgentMainTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,12 @@ public void testPreMain() throws Exception {
6060

6161
// the following are not available in all JVMs
6262
seenClasses.remove("sun/nio/ch/SocketChannelImpl");
63-
seenClasses.remove("java/net/AbstractPlainSocketImpl");
6463
seenClasses.remove("sun/nio/fs/UnixDirectoryStream");
6564
seenClasses.remove("sun/nio/fs/UnixSecureDirectoryStream");
65+
if (Runtime.version().feature() >= 19) {
66+
seenClasses.remove("java/net/AbstractPlainSocketImpl");
67+
seenClasses.remove("java/net/PlainSocketImpl");
68+
}
6669

6770
assertTrue(
6871
"Had classes in the spec which were not instrumented: " + seenClasses,

0 commit comments

Comments
 (0)