From 882a753883a5ba9a265db6de286a375b8045d621 Mon Sep 17 00:00:00 2001
From: Pieter Dirk Soels
Date: Tue, 6 Feb 2024 10:33:22 +0100
Subject: [PATCH] Flag inner `Thread` methods for JDK 19 and greater (#395)
Since JDK19, java.lang.Thread's methods have changed to support virtual threads. Specifically, for non-virtual threads, sleep(long) invokes sleep0(long) and yield() invokes yield0(). Moreover, since JDK21, sleep(long, int) and sleep(Duration) directly call sleep0(long) as opposed to sleep(long).
Now, to identify all blocking java.lang.Thread calls, BlockHound will flag invocations of sleep0(long) and yield0() as opposed to sleep(long) and yield() when running on JDK19 or greater.
Fixes #394.
---
.../java/reactor/blockhound/BlockHound.java | 23 ++++++++++++++-----
.../com/example/BlockingDisallowTest.java | 2 +-
.../test/java/com/example/ReactorTest.java | 4 ++--
3 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/agent/src/main/java/reactor/blockhound/BlockHound.java b/agent/src/main/java/reactor/blockhound/BlockHound.java
index ec20b03..6c3ba5d 100644
--- a/agent/src/main/java/reactor/blockhound/BlockHound.java
+++ b/agent/src/main/java/reactor/blockhound/BlockHound.java
@@ -134,12 +134,6 @@ public TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoa
public static class Builder {
private final Map>> blockingMethods = new HashMap>>() {{
- put("java/lang/Thread", new HashMap>() {{
- put("sleep", singleton("(J)V"));
- put("yield", singleton("()V"));
- put("onSpinWait", singleton("()V"));
- }});
-
put("java/lang/Object", new HashMap>() {{
put("wait", singleton("(J)V"));
}});
@@ -219,6 +213,23 @@ public static class Builder {
put("forkAndExec", singleton("(I[B[B[BI[BI[B[IZ)I"));
}});
}
+
+ try {
+ // Check if Java 19+
+ Class.forName("java.lang.WrongThreadException");
+
+ put("java/lang/Thread", new HashMap>() {{
+ put("sleep0", singleton("(J)V"));
+ put("yield0", singleton("()V"));
+ put("onSpinWait", singleton("()V"));
+ }});
+ } catch (ClassNotFoundException __) {
+ put("java/lang/Thread", new HashMap>() {{
+ put("sleep", singleton("(J)V"));
+ put("yield", singleton("()V"));
+ put("onSpinWait", singleton("()V"));
+ }});
+ }
}};
private final Map> allowances = new HashMap>() {{
diff --git a/example/src/test/java/com/example/BlockingDisallowTest.java b/example/src/test/java/com/example/BlockingDisallowTest.java
index 1120a58..e5512a0 100644
--- a/example/src/test/java/com/example/BlockingDisallowTest.java
+++ b/example/src/test/java/com/example/BlockingDisallowTest.java
@@ -58,7 +58,7 @@ public void shouldDisallow() throws InterruptedException {
//given the configuration we expect that Thread.yield() is allowed, but Thread.sleep() inside inner() isn't
assertThat(boeRef.get())
.isNotNull()
- .hasMessage("Blocking call! java.lang.Thread.sleep")
+ .hasMessageContaining("Blocking call! java.lang.Thread.sleep")
.hasStackTraceContaining("at com.example.BlockingDisallowTest$NonBlockingClass.inner")
.hasStackTraceContaining("at com.example.BlockingDisallowTest$NonBlockingClass.outer");
}
diff --git a/example/src/test/java/com/example/ReactorTest.java b/example/src/test/java/com/example/ReactorTest.java
index 7b4b77d..cd91bcf 100644
--- a/example/src/test/java/com/example/ReactorTest.java
+++ b/example/src/test/java/com/example/ReactorTest.java
@@ -124,14 +124,14 @@ public static Iterable