From 62dd2919da10d9cb79f3442c04f3e13971f417c3 Mon Sep 17 00:00:00 2001 From: Pierre De Rop Date: Wed, 17 Apr 2024 14:19:36 +0200 Subject: [PATCH] Detect jdk major version using Runtime class (#408) in #407, the BlockHound class is detecting the current jdk major version using InstrumentationUtil.jdkMajorVersion() method that has been introduced in #407 PR (the new InstrumentationUtil.jdkMajorVersion() method is relying on the jdk Runtime.getRuntime() class). Now, there is still another class (NativeWrappingClassFileTransformer) which needs to determine the current jdk major version. Let's update it in order to reuse the InstrumentationUtil instead of relying of java system properties. --- .../java/reactor/blockhound/BlockHound.java | 8 ++--- .../blockhound/InstrumentationUtils.java | 30 +++++++++++-------- .../NativeWrappingClassFileTransformer.java | 10 ++----- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/agent/src/main/java/reactor/blockhound/BlockHound.java b/agent/src/main/java/reactor/blockhound/BlockHound.java index 60be4eb..60d0d55 100644 --- a/agent/src/main/java/reactor/blockhound/BlockHound.java +++ b/agent/src/main/java/reactor/blockhound/BlockHound.java @@ -134,8 +134,6 @@ public TypePool typePool(ClassFileLocator classFileLocator, ClassLoader classLoa public static class Builder { private final Map>> blockingMethods = new HashMap>>() {{ - int jdkMajorVersion = InstrumentationUtils.getJdkMajorVersion(); - put("java/lang/Object", new HashMap>() {{ put("wait", singleton("(J)V")); }}); @@ -196,7 +194,7 @@ public static class Builder { put("writeBytes", singleton("([BIIZ)V")); }}); - if (jdkMajorVersion >= 9) { + if (InstrumentationUtils.jdkMajorVersion >= 9) { put("jdk/internal/misc/Unsafe", new HashMap>() {{ put("park", singleton("(ZJ)V")); }}); @@ -213,7 +211,7 @@ public static class Builder { }}); } - if (jdkMajorVersion < 19) { + if (InstrumentationUtils.jdkMajorVersion < 19) { // for jdk version < 19, the native method for Thread.sleep is "sleep" put("java/lang/Thread", new HashMap>() {{ put("sleep", singleton("(J)V")); @@ -221,7 +219,7 @@ public static class Builder { put("onSpinWait", singleton("()V")); }}); } - else if (jdkMajorVersion >= 19 && jdkMajorVersion <= 21) { + else if (InstrumentationUtils.jdkMajorVersion >= 19 && InstrumentationUtils.jdkMajorVersion <= 21) { // for jdk version in the range [19, 21], the native method for Thread.sleep is "sleep0" put("java/lang/Thread", new HashMap>() {{ put("sleep0", singleton("(J)V")); diff --git a/agent/src/main/java/reactor/blockhound/InstrumentationUtils.java b/agent/src/main/java/reactor/blockhound/InstrumentationUtils.java index c88c2b4..0504d84 100644 --- a/agent/src/main/java/reactor/blockhound/InstrumentationUtils.java +++ b/agent/src/main/java/reactor/blockhound/InstrumentationUtils.java @@ -34,6 +34,20 @@ class InstrumentationUtils { + /** + * Constant used to indicate the current JDK major version (8,9,..22,...) + */ + static final int jdkMajorVersion; + + static { + try { + jdkMajorVersion = getJdkMajorVersion(); + } + catch (InvocationTargetException | IllegalAccessException e) { + throw new ExceptionInInitializerError(e); + } + } + static void injectBootstrapClasses(Instrumentation instrumentation, String... classNames) throws IOException { File tempJarFile = File.createTempFile("BlockHound", ".jar"); tempJarFile.deleteOnExit(); @@ -83,7 +97,7 @@ public void visit(int version, int access, String name, String signature, String * * @return the current jdk major version (8, 9, 10, ... 22) */ - static int getJdkMajorVersion() { + private static int getJdkMajorVersion() throws InvocationTargetException, IllegalAccessException { Object version = getRuntimeVersion(); if (version == null) { @@ -98,7 +112,7 @@ static int getJdkMajorVersion() { * * @return the detected JDK version object or null if not available */ - private static Object getRuntimeVersion() { + private static Object getRuntimeVersion() throws InvocationTargetException, IllegalAccessException { Runtime runtime = Runtime.getRuntime(); try { Method versionMethod = runtime.getClass().getMethod("version"); @@ -109,11 +123,6 @@ private static Object getRuntimeVersion() { // Method Runtime.version() not found -> return null, meaning JDK 8 return null; // JDK 8 } - - catch (IllegalAccessException | InvocationTargetException e) { - // if the Runtime.version() method exists, we should be able to invoke it, consider this is an error state - throw new IllegalStateException("Could not invoke Runtime.version() method", e); - } } /** @@ -122,7 +131,7 @@ private static Object getRuntimeVersion() { * @param version the JDK version object * @return the major version (9, 10, ...) */ - private static int getRuntimeVersionFeature(Object version) { + private static int getRuntimeVersionFeature(Object version) throws InvocationTargetException, IllegalAccessException { try { Method featureMethod = version.getClass().getMethod("feature"); Object feature = featureMethod.invoke(version); @@ -133,11 +142,6 @@ private static int getRuntimeVersionFeature(Object version) { // Version.feature() method not found -> JDK 9 (because feature method is only available starting from JDK10 +) return 9; } - - catch (IllegalAccessException | InvocationTargetException e) { - // if the Runtime.version().feature() method exists, we should be able to invoke it, consider this is an error state - throw new IllegalStateException("Could not invoke Runtime.version().feature() method", e); - } } } diff --git a/agent/src/main/java/reactor/blockhound/NativeWrappingClassFileTransformer.java b/agent/src/main/java/reactor/blockhound/NativeWrappingClassFileTransformer.java index 7e72d40..f15d0ad 100644 --- a/agent/src/main/java/reactor/blockhound/NativeWrappingClassFileTransformer.java +++ b/agent/src/main/java/reactor/blockhound/NativeWrappingClassFileTransformer.java @@ -36,13 +36,7 @@ class NativeWrappingClassFileTransformer implements ClassFileTransformer { private final Map>> blockingMethods; - public static final boolean IS_JDK_18_OR_NEWER; - - static { - String javaVersion = System.getProperty("java.specification.version"); - double version = Double.parseDouble(javaVersion); - IS_JDK_18_OR_NEWER = version >= 18.0; - } + private static final int JDK_18 = 18; NativeWrappingClassFileTransformer(final Map>> blockingMethods) { this.blockingMethods = blockingMethods; @@ -116,7 +110,7 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str @Override public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { // See #392 - if (IS_JDK_18_OR_NEWER && descriptor.equals("Ljdk/internal/vm/annotation/IntrinsicCandidate;")) { + if (InstrumentationUtils.jdkMajorVersion >= JDK_18 && descriptor.equals("Ljdk/internal/vm/annotation/IntrinsicCandidate;")) { return null; // remove the intrinsic annotation } return super.visitAnnotation(descriptor, visible);