Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions utils/src/main/java/datadog/instrument/utils/ClassNameFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,22 +154,22 @@ public static ClassNameFilter readFrom(DataInput in) throws IOException {
* Computes a 32-bit 'class-code' that includes the length of the package-prefix and simple-name,
* plus the first and last characters of the simple-name (each truncated to fit into 8-bits.)
*/
private static int classCode(String className) {
int start = className.lastIndexOf('.') + 1;
int end = className.length() - 1;
return (0xFF & className.charAt(end)) << 24
| (0xFF & className.charAt(start)) << 16
private static int classCode(String name) {
int start = name.lastIndexOf('.') + 1;
int end = name.length() - 1;
return (0xFF & name.charAt(end)) << 24
| (0xFF & name.charAt(start)) << 16
| (0xFF & (end - start)) << 8
| (0xFF & start);
}

/** Checks whether the 32-bit 'class-code' is consistent with the fully-qualified class-name. */
private static boolean checkClassCode(CharSequence className, int code) {
int start = (0xFF & code);
int end = className.length() - 1;
return end - start == (0xFF & (code >> 8))
&& className.charAt(start) == (0xFF & (code >> 16))
&& className.charAt(end) == (0xFF & (code >> 24));
private static boolean checkClassCode(CharSequence name, int code) {
int start = 0xFF & code;
int end = name.length() - 1;
// Keep the sign bit so a start beyond the end cannot match the encoded length.
return (0x800000FF & (end - start)) == (0xFF & (code >> 8))
&& (((name.charAt(start) ^ code >>> 16) | (name.charAt(end) ^ code >>> 24)) & 0xFF) == 0;
}

private static int rehash(int oldHash) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,52 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class ClassNameFilterTest {

@ParameterizedTest
@ValueSource(strings = {"example.例", "example.例Class", "example.My例"})
void unicodeClassNames(String className) {
ClassNameFilter filter = new ClassNameFilter(256);

filter.add(className);

assertTrue(filter.contains(className));
}

@ParameterizedTest
@ValueSource(ints = {256, 257, 512, 513})
void longSimpleNames(int length) {
char[] simpleName = new char[length];
Arrays.fill(simpleName, 'A');
String className = "example." + new String(simpleName);
ClassNameFilter filter = new ClassNameFilter(256);

filter.add(className);

assertTrue(filter.contains(className));
}

@Test
void shorterHashCollisionDoesNotReadPastClassName() {
char[] padding = new char[248];
Arrays.fill(padding, 'A');
String className = "a." + new String(padding) + "DVYRQBJ";
assertEquals("A".hashCode(), className.hashCode());
ClassNameFilter filter = new ClassNameFilter(256);

filter.add(className);

assertFalse(filter.contains("A"));
assertTrue(filter.contains(className));
}

@Test
void basicOperation() {
ClassNameFilter filter = new ClassNameFilter(8 * 1024 * 1024);
Expand Down
Loading