-
Notifications
You must be signed in to change notification settings - Fork 850
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix missing unsafe available check (#6920)
- Loading branch information
Showing
3 changed files
with
106 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,6 +67,9 @@ testing { | |
} | ||
} | ||
} | ||
suites { | ||
register<JvmTestSuite>("testWithoutUnsafe") {} | ||
} | ||
} | ||
|
||
tasks { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
...outUnsafe/java/io/opentelemetry/exporter/internal/marshal/StatelessMarshalerUtilTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.exporter.internal.marshal; | ||
|
||
import static io.opentelemetry.exporter.internal.marshal.StatelessMarshalerUtil.getUtf8Size; | ||
import static io.opentelemetry.exporter.internal.marshal.StatelessMarshalerUtil.writeUtf8; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.nio.charset.StandardCharsets; | ||
import org.junit.jupiter.api.Test; | ||
|
||
class StatelessMarshalerUtilTest { | ||
|
||
// Simulate running in an environment without sun.misc.Unsafe e.g. when running a modular | ||
// application. To use sun.misc.Unsafe in modular application user would need to add dependency to | ||
// jdk.unsupported module or use --add-modules jdk.unsupported. Here we use a custom child first | ||
// class loader that does not delegate loading sun.misc classes to make sun.misc.Unsafe | ||
// unavailable. | ||
@Test | ||
void encodeUtf8WithoutUnsafe() throws Exception { | ||
ClassLoader testClassLoader = | ||
new ClassLoader(this.getClass().getClassLoader()) { | ||
@Override | ||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { | ||
// don't allow loading sun.misc classes | ||
if (name.startsWith("sun.misc")) { | ||
throw new ClassNotFoundException(name); | ||
} | ||
// load io.opentelemetry in the custom loader | ||
if (name.startsWith("io.opentelemetry")) { | ||
synchronized (this) { | ||
Class<?> clazz = findLoadedClass(name); | ||
if (clazz != null) { | ||
return clazz; | ||
} | ||
try (InputStream inputStream = | ||
getParent().getResourceAsStream(name.replace(".", "/") + ".class")) { | ||
if (inputStream != null) { | ||
byte[] bytes = readBytes(inputStream); | ||
// we don't bother to define packages or provide protection domain | ||
return defineClass(name, bytes, 0, bytes.length); | ||
} | ||
} catch (IOException exception) { | ||
throw new ClassNotFoundException(name, exception); | ||
} | ||
} | ||
} | ||
return super.loadClass(name, resolve); | ||
} | ||
}; | ||
|
||
// load test class in the custom loader and run the test | ||
Class<?> testClass = testClassLoader.loadClass(this.getClass().getName() + "$TestClass"); | ||
assertThat(testClass.getClassLoader()).isEqualTo(testClassLoader); | ||
Runnable test = (Runnable) testClass.getConstructor().newInstance(); | ||
test.run(); | ||
} | ||
|
||
private static byte[] readBytes(InputStream inputStream) throws IOException { | ||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||
byte[] buffer = new byte[1024]; | ||
|
||
int readCount; | ||
while ((readCount = inputStream.read(buffer, 0, buffer.length)) != -1) { | ||
out.write(buffer, 0, readCount); | ||
} | ||
return out.toByteArray(); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class TestClass implements Runnable { | ||
|
||
@Override | ||
public void run() { | ||
// verify that unsafe can't be found | ||
assertThatThrownBy(() -> Class.forName("sun.misc.Unsafe")) | ||
.isInstanceOf(ClassNotFoundException.class); | ||
// test the methods that use unsafe | ||
assertThat(getUtf8Size("a", true)).isEqualTo(1); | ||
assertThat(testUtf8("a", 0)).isEqualTo("a"); | ||
} | ||
|
||
static String testUtf8(String string, int utf8Length) { | ||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { | ||
CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream); | ||
writeUtf8(codedOutputStream, string, utf8Length, true); | ||
codedOutputStream.flush(); | ||
return new String(outputStream.toByteArray(), StandardCharsets.UTF_8); | ||
} catch (Exception exception) { | ||
throw new IllegalArgumentException(exception); | ||
} | ||
} | ||
} | ||
} |