From a1d650a2b9903937bd90f3e2b1d5f7abf4993020 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Sat, 17 Oct 2026 15:15:57 +0100 Subject: [PATCH] Generate a zero-branch root for empty tries Encode the empty root sentinel when generating Java source from an empty mapping, so nonempty lookups return no match instead of reading past an empty array. Generate and compile an empty trie in a regression test and exercise both lookup overloads. --- .../instrument/utils/ClassNameTrie.java | 3 +++ .../instrument/utils/ClassNameTrieTest.java | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/utils/src/main/java/datadog/instrument/utils/ClassNameTrie.java b/utils/src/main/java/datadog/instrument/utils/ClassNameTrie.java index dc1bccf..5e3f617 100644 --- a/utils/src/main/java/datadog/instrument/utils/ClassNameTrie.java +++ b/utils/src/main/java/datadog/instrument/utils/ClassNameTrie.java @@ -1058,6 +1058,9 @@ public static boolean generateJavaTrie( int chunkSize = 0; StringBuilder buf = new StringBuilder(); buf.append(" \""); + if (trie.isEmpty()) { + buf.append("\\000"); // encode an empty root node with zero branches + } for (int i = 0; i < trie.trieLength; i++) { char c = trie.trieData[i]; if (++chunkSize > 10_000) { diff --git a/utils/src/test/java/datadog/instrument/utils/ClassNameTrieTest.java b/utils/src/test/java/datadog/instrument/utils/ClassNameTrieTest.java index 722202c..43e48be 100644 --- a/utils/src/test/java/datadog/instrument/utils/ClassNameTrieTest.java +++ b/utils/src/test/java/datadog/instrument/utils/ClassNameTrieTest.java @@ -166,6 +166,28 @@ void generateJavaSource(@TempDir File classesDir) throws Exception { assertEquals(5, trieApply.invoke(null, "com.foobar.Five")); } + @Test + void generateEmptyJavaSource(@TempDir File classesDir) throws Exception { + Files.createFile(new File(classesDir, "empty.trie").toPath()); + ClassNameTrie.JavaGenerator.main( + new String[] {classesDir.toString(), classesDir.toString(), "empty.trie"}); + + assertEquals( + 0, + getSystemJavaCompiler() + .run(null, null, null, new File(classesDir, "EmptyTrie.java").toString())); + + try (URLClassLoader cl = URLClassLoader.newInstance(new URL[] {classesDir.toURI().toURL()})) { + Class trieClass = cl.loadClass("EmptyTrie"); + Method apply = trieClass.getMethod("apply", String.class); + Method applyFromIndex = trieClass.getMethod("apply", String.class, int.class); + for (String key : new String[] {"", "a", "com.example.Type"}) { + assertEquals(-1, apply.invoke(null, key)); + assertEquals(-1, applyFromIndex.invoke(null, "prefix/" + key, 7)); + } + } + } + @Test @SuppressWarnings("UnnecessaryUnicodeEscape") void manual() throws IOException {