diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index eee1c6f5d..c54ef829e 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -46,6 +46,16 @@ jobs: export LIBC=glibc export JAVA_TEST_HOME=$(pwd)/test_jdk export SANITIZER=${{ matrix.config }} + export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ { + split($2, v, "[._]"); + if (v[1] == "1") { + # Java 8 or older: Include major, minor, and update + printf "%s.%s.%s\n", v[2], v[3], v[4] + } else { + # Java 9 or newer: Major, minor, and patch + printf "%s.%s.%s\n", v[1], v[2], v[3] + } + }') ./gradlew :ddprof-test:test${{ matrix.config }} if [ $? -ne 0 ]; then echo "glibc-${{ matrix.java_version }}-${{ matrix.config }}" >> failures_glibc-${{ matrix.java_version }}-${{ matrix.config }}.txt @@ -109,6 +119,16 @@ jobs: export JAVA_HOME=$JAVA_HOME export PATH=$JAVA_HOME/bin:$PATH export SANITIZER=${{ matrix.config }} + export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ { + split($2, v, "[._]"); + if (v[1] == "1") { + # Java 8 or older: Include major, minor, and update + printf "%s.%s.%s\n", v[2], v[3], v[4] + } else { + # Java 9 or newer: Major, minor, and patch + printf "%s.%s.%s\n", v[1], v[2], v[3] + } + }') ./gradlew :ddprof-test:test${{ matrix.config }} if [ $? -ne 0 ]; then echo "ubuntu-jdk-${{ matrix.java_version }}-${{ matrix.config }}" >> failures_ubuntu-jdk-${{ matrix.java_version }}-${{ matrix.config }}.txt @@ -169,6 +189,16 @@ jobs: export TEST_CONFIGURATION=glibc/${{ matrix.java_version }} export LIBC=glibc export SANITIZER=${{ matrix.config }} + export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ { + split($2, v, "[._]"); + if (v[1] == "1") { + # Java 8 or older: Include major, minor, and update + printf "%s.%s.%s\n", v[2], v[3], v[4] + } else { + # Java 9 or newer: Major, minor, and patch + printf "%s.%s.%s\n", v[1], v[2], v[3] + } + }') chmod a+x gradlew ./gradlew :ddprof-test:test${{ matrix.config }} if [ $? -ne 0 ]; then @@ -233,6 +263,16 @@ jobs: export JAVA_HOME=$JAVA_HOME export PATH=$JAVA_HOME/bin:$PATH export SANITIZER=${{ matrix.config }} + export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ { + split($2, v, "[._]"); + if (v[1] == "1") { + # Java 8 or older: Include major, minor, and update + printf "%s.%s.%s\n", v[2], v[3], v[4] + } else { + # Java 9 or newer: Major, minor, and patch + printf "%s.%s.%s\n", v[1], v[2], v[3] + } + }') ./gradlew :ddprof-test:test${{ matrix.config }} if [ $? -ne 0 ]; then echo "glibc-oracle8-${{ matrix.config }}" >> failures_glibc-oracle8-${{ matrix.config }}.txt @@ -295,6 +335,16 @@ jobs: export LIBC=musl export JAVA_TEST_HOME=$(pwd)/test_jdk export SANITIZER=${{ matrix.config }} + export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ { + split($2, v, "[._]"); + if (v[1] == "1") { + # Java 8 or older: Include major, minor, and update + printf "%s.%s.%s\n", v[2], v[3], v[4] + } else { + # Java 9 or newer: Major, minor, and patch + printf "%s.%s.%s\n", v[1], v[2], v[3] + } + }') ./gradlew :ddprof-test:test${{ matrix.config }} if [ $? -ne 0 ]; then echo "musl-${{ matrix.java_version }}-${{ matrix.config }}" >> failures_musl-${{ matrix.java_version }}-${{ matrix.config }}.txt @@ -380,6 +430,16 @@ jobs: export JAVA_HOME=$JAVA_HOME export PATH=$JAVA_HOME/bin:$PATH export SANITIZER=${{ matrix.config }} + export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ { + split($2, v, "[._]"); + if (v[1] == "1") { + # Java 8 or older: Include major, minor, and update + printf "%s.%s.%s\n", v[2], v[3], v[4] + } else { + # Java 9 or newer: Major, minor, and patch + printf "%s.%s.%s\n", v[1], v[2], v[3] + } + }') ./gradlew :ddprof-test:test${{ matrix.config }} if [ $? -ne 0 ]; then echo "glibc-zing-${{ matrix.java_version }}-${{ matrix.config }}" >> failures_zing-${{ matrix.java_version }}-${{ matrix.config }}.txt diff --git a/ddprof-lib/src/main/cpp/vmEntry.cpp b/ddprof-lib/src/main/cpp/vmEntry.cpp index 4190b5555..dcd42f7ac 100644 --- a/ddprof-lib/src/main/cpp/vmEntry.cpp +++ b/ddprof-lib/src/main/cpp/vmEntry.cpp @@ -95,12 +95,18 @@ static void resolveMethodIdEnd() {} JavaFullVersion JavaVersionAccess::get_java_version(char* prop_value) { JavaFullVersion version = {8, 362}; // initial value is 8u362; an arbitrary java version - if (strncmp(prop_value, "1.8.0", 5) == 0) { + TEST_LOG("version property: %s", prop_value); + if (strncmp(prop_value, "1.8.0_", 6) == 0) { version.major = 8; version.update = atoi(prop_value + 6); } else if (strncmp(prop_value, "8.0.", 4) == 0) { version.major = 8; version.update = atoi(prop_value + 4); + } else if (strncmp(prop_value, "25.", 3) == 0 && prop_value[3] != '0') { + // Java 8 encoded in java.vm.version system property looks like 25.352-b08 + // The upcoming Java 25 version will have a form of '25.0.' instead + version.major = 8; + version.update = atoi(prop_value + 3); } else if (strncmp(prop_value, "JRE 1.8.0", 9) == 0) { // IBM JDK 8 does not report the 'real' version in any property accessible // from JVMTI The only piece of info we can use has the following format @@ -108,7 +114,6 @@ JavaFullVersion JavaVersionAccess::get_java_version(char* prop_value) { // Considering that JDK 8.0.361 is the only release in 2023 we can use // that part of the version string to pretend anything after year 2023 // inclusive is 8.0.361. Not perfect, but this is the only thing we have. - JavaFullVersion version; version.major = 8; char *idx = strstr(prop_value, " 202"); if (idx != NULL) { @@ -234,6 +239,7 @@ bool VM::initShared(JavaVM* vm) { } } } + TEST_LOG("java.runtime.version: %s", prop); if (prop != NULL) { JavaFullVersion version = JavaVersionAccess::get_java_version(prop); _java_version = version.major; @@ -242,6 +248,12 @@ bool VM::initShared(JavaVM* vm) { prop = NULL; } if (_jvmti->GetSystemProperty("java.vm.version", &prop) == 0) { + TEST_LOG("java.vm.version: %s", prop); + if (_java_version == 0) { + JavaFullVersion version = JavaVersionAccess::get_java_version(prop); + _java_version = version.major; + _java_update_version = version.update; + } _hotspot_version = JavaVersionAccess::get_hotspot_version(prop); _jvmti->Deallocate((unsigned char *)prop); prop = NULL; @@ -256,6 +268,7 @@ bool VM::initShared(JavaVM* vm) { // - if we failed to resolve the _java_version but have _hotspot_version, let's use the hotspot version as java version _java_version = _hotspot_version; } + TEST_LOG("jvm_version#%d.%d.%d", _java_version, 0, _java_update_version); CodeCache *lib = openJvmLibrary(); if (lib == nullptr) { diff --git a/ddprof-test/src/test/java/com/datadoghq/profiler/JVMAccessTest.java b/ddprof-test/src/test/java/com/datadoghq/profiler/JVMAccessTest.java index d3cdbf706..ec18bf50e 100644 --- a/ddprof-test/src/test/java/com/datadoghq/profiler/JVMAccessTest.java +++ b/ddprof-test/src/test/java/com/datadoghq/profiler/JVMAccessTest.java @@ -56,6 +56,47 @@ void sanityInitailizationTest() throws Exception { assertFalse(initProfilerFound, "initProfilerBridge found"); } + @Test + void jvmVersionTest() throws Exception { + String config = System.getProperty("ddprof_test.config"); + assumeTrue("debug".equals(config)); + + String javaVersion = System.getenv("JAVA_VERSION"); + assumeTrue(javaVersion != null); + + String javaHome = System.getenv("JAVA_TEST_HOME"); + if (javaHome == null) { + javaHome = System.getenv("JAVA_HOME"); + } + if (javaHome == null) { + javaHome = System.getProperty("java.home"); + } + assertNotNull(javaHome); + + File outFile = Files.createTempFile("jvmaccess", ".out").toFile(); + outFile.deleteOnExit(); + File errFile = Files.createTempFile("jvmaccess", ".err").toFile(); + errFile.deleteOnExit(); + + ProcessBuilder pb = new ProcessBuilder(javaHome + "/bin/java", "-cp", System.getProperty("java.class.path"), ExternalLauncher.class.getName(), "library"); + pb.redirectOutput(outFile); + pb.redirectError(errFile); + Process p = pb.start(); + int val = p.waitFor(); + assertEquals(0, val); + + String foundVersion = null; + for (String line : Files.readAllLines(outFile.toPath())) { + System.err.println(line); + if (line.contains("[TEST::INFO] jvm_version#")) { + foundVersion = line.split("#")[1]; + break; + } + } + assertNotNull(foundVersion, "java version not found in logs"); + assertEquals(javaVersion, foundVersion, "invalid java version"); + } + @Test void testGetFlag() { JVMAccess.Flags flags = JVMAccess.getInstance().flags();