Skip to content

Commit d8ad9f2

Browse files
authored
Add sanity test for Java version retrieval in native code (#153)
1 parent c725997 commit d8ad9f2

File tree

3 files changed

+116
-2
lines changed

3 files changed

+116
-2
lines changed

.github/workflows/test_workflow.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ jobs:
4646
export LIBC=glibc
4747
export JAVA_TEST_HOME=$(pwd)/test_jdk
4848
export SANITIZER=${{ matrix.config }}
49+
export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ {
50+
split($2, v, "[._]");
51+
if (v[1] == "1") {
52+
# Java 8 or older: Include major, minor, and update
53+
printf "%s.%s.%s\n", v[2], v[3], v[4]
54+
} else {
55+
# Java 9 or newer: Major, minor, and patch
56+
printf "%s.%s.%s\n", v[1], v[2], v[3]
57+
}
58+
}')
4959
./gradlew :ddprof-test:test${{ matrix.config }}
5060
if [ $? -ne 0 ]; then
5161
echo "glibc-${{ matrix.java_version }}-${{ matrix.config }}" >> failures_glibc-${{ matrix.java_version }}-${{ matrix.config }}.txt
@@ -109,6 +119,16 @@ jobs:
109119
export JAVA_HOME=$JAVA_HOME
110120
export PATH=$JAVA_HOME/bin:$PATH
111121
export SANITIZER=${{ matrix.config }}
122+
export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ {
123+
split($2, v, "[._]");
124+
if (v[1] == "1") {
125+
# Java 8 or older: Include major, minor, and update
126+
printf "%s.%s.%s\n", v[2], v[3], v[4]
127+
} else {
128+
# Java 9 or newer: Major, minor, and patch
129+
printf "%s.%s.%s\n", v[1], v[2], v[3]
130+
}
131+
}')
112132
./gradlew :ddprof-test:test${{ matrix.config }}
113133
if [ $? -ne 0 ]; then
114134
echo "ubuntu-jdk-${{ matrix.java_version }}-${{ matrix.config }}" >> failures_ubuntu-jdk-${{ matrix.java_version }}-${{ matrix.config }}.txt
@@ -169,6 +189,16 @@ jobs:
169189
export TEST_CONFIGURATION=glibc/${{ matrix.java_version }}
170190
export LIBC=glibc
171191
export SANITIZER=${{ matrix.config }}
192+
export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ {
193+
split($2, v, "[._]");
194+
if (v[1] == "1") {
195+
# Java 8 or older: Include major, minor, and update
196+
printf "%s.%s.%s\n", v[2], v[3], v[4]
197+
} else {
198+
# Java 9 or newer: Major, minor, and patch
199+
printf "%s.%s.%s\n", v[1], v[2], v[3]
200+
}
201+
}')
172202
chmod a+x gradlew
173203
./gradlew :ddprof-test:test${{ matrix.config }}
174204
if [ $? -ne 0 ]; then
@@ -233,6 +263,16 @@ jobs:
233263
export JAVA_HOME=$JAVA_HOME
234264
export PATH=$JAVA_HOME/bin:$PATH
235265
export SANITIZER=${{ matrix.config }}
266+
export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ {
267+
split($2, v, "[._]");
268+
if (v[1] == "1") {
269+
# Java 8 or older: Include major, minor, and update
270+
printf "%s.%s.%s\n", v[2], v[3], v[4]
271+
} else {
272+
# Java 9 or newer: Major, minor, and patch
273+
printf "%s.%s.%s\n", v[1], v[2], v[3]
274+
}
275+
}')
236276
./gradlew :ddprof-test:test${{ matrix.config }}
237277
if [ $? -ne 0 ]; then
238278
echo "glibc-oracle8-${{ matrix.config }}" >> failures_glibc-oracle8-${{ matrix.config }}.txt
@@ -295,6 +335,16 @@ jobs:
295335
export LIBC=musl
296336
export JAVA_TEST_HOME=$(pwd)/test_jdk
297337
export SANITIZER=${{ matrix.config }}
338+
export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ {
339+
split($2, v, "[._]");
340+
if (v[1] == "1") {
341+
# Java 8 or older: Include major, minor, and update
342+
printf "%s.%s.%s\n", v[2], v[3], v[4]
343+
} else {
344+
# Java 9 or newer: Major, minor, and patch
345+
printf "%s.%s.%s\n", v[1], v[2], v[3]
346+
}
347+
}')
298348
./gradlew :ddprof-test:test${{ matrix.config }}
299349
if [ $? -ne 0 ]; then
300350
echo "musl-${{ matrix.java_version }}-${{ matrix.config }}" >> failures_musl-${{ matrix.java_version }}-${{ matrix.config }}.txt
@@ -380,6 +430,16 @@ jobs:
380430
export JAVA_HOME=$JAVA_HOME
381431
export PATH=$JAVA_HOME/bin:$PATH
382432
export SANITIZER=${{ matrix.config }}
433+
export JAVA_VERSION=$(${JAVA_TEST_HOME}/bin/java -version 2>&1 | awk -F '"' '/version/ {
434+
split($2, v, "[._]");
435+
if (v[1] == "1") {
436+
# Java 8 or older: Include major, minor, and update
437+
printf "%s.%s.%s\n", v[2], v[3], v[4]
438+
} else {
439+
# Java 9 or newer: Major, minor, and patch
440+
printf "%s.%s.%s\n", v[1], v[2], v[3]
441+
}
442+
}')
383443
./gradlew :ddprof-test:test${{ matrix.config }}
384444
if [ $? -ne 0 ]; then
385445
echo "glibc-zing-${{ matrix.java_version }}-${{ matrix.config }}" >> failures_zing-${{ matrix.java_version }}-${{ matrix.config }}.txt

ddprof-lib/src/main/cpp/vmEntry.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,20 +95,25 @@ static void resolveMethodIdEnd() {}
9595

9696
JavaFullVersion JavaVersionAccess::get_java_version(char* prop_value) {
9797
JavaFullVersion version = {8, 362}; // initial value is 8u362; an arbitrary java version
98-
if (strncmp(prop_value, "1.8.0", 5) == 0) {
98+
TEST_LOG("version property: %s", prop_value);
99+
if (strncmp(prop_value, "1.8.0_", 6) == 0) {
99100
version.major = 8;
100101
version.update = atoi(prop_value + 6);
101102
} else if (strncmp(prop_value, "8.0.", 4) == 0) {
102103
version.major = 8;
103104
version.update = atoi(prop_value + 4);
105+
} else if (strncmp(prop_value, "25.", 3) == 0 && prop_value[3] != '0') {
106+
// Java 8 encoded in java.vm.version system property looks like 25.352-b08
107+
// The upcoming Java 25 version will have a form of '25.0.<update>' instead
108+
version.major = 8;
109+
version.update = atoi(prop_value + 3);
104110
} else if (strncmp(prop_value, "JRE 1.8.0", 9) == 0) {
105111
// IBM JDK 8 does not report the 'real' version in any property accessible
106112
// from JVMTI The only piece of info we can use has the following format
107113
// `JRE 1.8.0 <some text> 20230313_47323 <some more text>`
108114
// Considering that JDK 8.0.361 is the only release in 2023 we can use
109115
// that part of the version string to pretend anything after year 2023
110116
// inclusive is 8.0.361. Not perfect, but this is the only thing we have.
111-
JavaFullVersion version;
112117
version.major = 8;
113118
char *idx = strstr(prop_value, " 202");
114119
if (idx != NULL) {
@@ -234,6 +239,7 @@ bool VM::initShared(JavaVM* vm) {
234239
}
235240
}
236241
}
242+
TEST_LOG("java.runtime.version: %s", prop);
237243
if (prop != NULL) {
238244
JavaFullVersion version = JavaVersionAccess::get_java_version(prop);
239245
_java_version = version.major;
@@ -242,6 +248,12 @@ bool VM::initShared(JavaVM* vm) {
242248
prop = NULL;
243249
}
244250
if (_jvmti->GetSystemProperty("java.vm.version", &prop) == 0) {
251+
TEST_LOG("java.vm.version: %s", prop);
252+
if (_java_version == 0) {
253+
JavaFullVersion version = JavaVersionAccess::get_java_version(prop);
254+
_java_version = version.major;
255+
_java_update_version = version.update;
256+
}
245257
_hotspot_version = JavaVersionAccess::get_hotspot_version(prop);
246258
_jvmti->Deallocate((unsigned char *)prop);
247259
prop = NULL;
@@ -256,6 +268,7 @@ bool VM::initShared(JavaVM* vm) {
256268
// - if we failed to resolve the _java_version but have _hotspot_version, let's use the hotspot version as java version
257269
_java_version = _hotspot_version;
258270
}
271+
TEST_LOG("jvm_version#%d.%d.%d", _java_version, 0, _java_update_version);
259272

260273
CodeCache *lib = openJvmLibrary();
261274
if (lib == nullptr) {

ddprof-test/src/test/java/com/datadoghq/profiler/JVMAccessTest.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,47 @@ void sanityInitailizationTest() throws Exception {
5656
assertFalse(initProfilerFound, "initProfilerBridge found");
5757
}
5858

59+
@Test
60+
void jvmVersionTest() throws Exception {
61+
String config = System.getProperty("ddprof_test.config");
62+
assumeTrue("debug".equals(config));
63+
64+
String javaVersion = System.getenv("JAVA_VERSION");
65+
assumeTrue(javaVersion != null);
66+
67+
String javaHome = System.getenv("JAVA_TEST_HOME");
68+
if (javaHome == null) {
69+
javaHome = System.getenv("JAVA_HOME");
70+
}
71+
if (javaHome == null) {
72+
javaHome = System.getProperty("java.home");
73+
}
74+
assertNotNull(javaHome);
75+
76+
File outFile = Files.createTempFile("jvmaccess", ".out").toFile();
77+
outFile.deleteOnExit();
78+
File errFile = Files.createTempFile("jvmaccess", ".err").toFile();
79+
errFile.deleteOnExit();
80+
81+
ProcessBuilder pb = new ProcessBuilder(javaHome + "/bin/java", "-cp", System.getProperty("java.class.path"), ExternalLauncher.class.getName(), "library");
82+
pb.redirectOutput(outFile);
83+
pb.redirectError(errFile);
84+
Process p = pb.start();
85+
int val = p.waitFor();
86+
assertEquals(0, val);
87+
88+
String foundVersion = null;
89+
for (String line : Files.readAllLines(outFile.toPath())) {
90+
System.err.println(line);
91+
if (line.contains("[TEST::INFO] jvm_version#")) {
92+
foundVersion = line.split("#")[1];
93+
break;
94+
}
95+
}
96+
assertNotNull(foundVersion, "java version not found in logs");
97+
assertEquals(javaVersion, foundVersion, "invalid java version");
98+
}
99+
59100
@Test
60101
void testGetFlag() {
61102
JVMAccess.Flags flags = JVMAccess.getInstance().flags();

0 commit comments

Comments
 (0)