diff --git a/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java b/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java index d475bd218..b61c9df60 100644 --- a/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java +++ b/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java @@ -100,7 +100,7 @@ final class CustomFilterGroup extends StringFilterGroup { */ class ByteArrayFilterGroup extends FilterGroup { - private int[][] failurePatterns; + private volatile int[][] failurePatterns; // Modified implementation from https://stackoverflow.com/a/1507813 private static int indexOf(final byte[] data, final byte[] pattern, final int[] failure) { @@ -143,13 +143,15 @@ class ByteArrayFilterGroup extends FilterGroup { super(setting, filters); } - private void buildFailurePatterns() { + private synchronized void buildFailurePatterns() { + if (failurePatterns != null) return; // Thread race and another thread already initialized the search. LogHelper.printDebug(() -> "Building failure array for: " + this); - failurePatterns = new int[filters.length][]; + int[][] failurePatterns = new int[filters.length][]; int i = 0; for (byte[] pattern : filters) { failurePatterns[i++] = createFailurePattern(pattern); } + this.failurePatterns = failurePatterns; // Must set after initialization finishes. } @Override @@ -185,7 +187,7 @@ abstract class FilterGroupList> implements Iterable< /** * Search graph. Created only if needed. */ - private TrieSearch search; + private volatile TrieSearch search; @SafeVarargs protected final void addAll(final T... groups) { @@ -193,9 +195,11 @@ abstract class FilterGroupList> implements Iterable< search = null; // Rebuild, if already created. } - protected final void buildSearch() { + protected final synchronized void buildSearch() { + // Since litho filtering is multi-threaded, this method can be concurrently called by multiple threads. + if (search != null) return; // Thread race and another thread already initialized the search. LogHelper.printDebug(() -> "Creating prefix search tree for: " + this); - search = createSearchGraph(); + TrieSearch search = createSearchGraph(); for (T group : filterGroups) { if (!group.includeInSearch()) { continue; @@ -212,6 +216,7 @@ abstract class FilterGroupList> implements Iterable< }); } } + this.search = search; // Must set after it's completely initialized. } @NonNull