Skip to content

Bug fixes: incorrect keep directive, race condition, and improve logging#88

Merged
eed3si9n merged 4 commits intoeed3si9n:developfrom
holtherndon-stripe:holtherndon/bug-fixes
Jan 20, 2026
Merged

Bug fixes: incorrect keep directive, race condition, and improve logging#88
eed3si9n merged 4 commits intoeed3si9n:developfrom
holtherndon-stripe:holtherndon/bug-fixes

Conversation

@holtherndon-stripe
Copy link
Copy Markdown
Contributor

tl;dr: Fixes a set of bugs we encountered when attempting to update to the latest version internally. Also added some additional logging that was useful when debugging jarjar in Bazel.

1) Incorrect keep directive

As mentioned in #55, the keep directive is not correctly including the transitive deps of a class. Due to the added return false; in KeepProcessor#process, any class that did not explicitly match the keep pattern would be removed from the final jar. This differs from the original expected behavior which collects the final class exclusion via the getExcludes method to be removed after processing rather than during.

To fix this, I've removed the return false. (And for readability, replaced the return true in the pattern loop with a break.

2) Race condition

Stacktrace:

[KeepProcessor] Error reading scala/collection/mutable/ArrayOps$ofLong.class: Cannot invoke "java.util.HashMap.put(Object, Object)" because "this.map" is null
java.lang.NullPointerException: Cannot invoke "java.util.HashMap.put(Object, Object)" because "this.map" is null
        at java.base/java.util.HashSet.add(HashSet.java:221)
        at com.eed3si9n.jarjar.KeepProcessor.map(KeepProcessor.java:87)
        at org.objectweb.asm.commons.Remapper.mapType(Remapper.java:127)
        at org.objectweb.asm.commons.Remapper.mapDesc(Remapper.java:104)
        at org.objectweb.asm.commons.MethodRemapper.visitLocalVariable(MethodRemapper.java:249)
        at org.objectweb.asm.ClassReader.readCode(ClassReader.java:2593)
        at org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1512)
        at org.objectweb.asm.ClassReader.accept(ClassReader.java:745)
        at org.objectweb.asm.ClassReader.accept(ClassReader.java:425)
        at com.eed3si9n.jarjar.KeepProcessor.process(KeepProcessor.java:66)
        at com.eed3si9n.jarjar.util.JarProcessorChain.process(JarProcessorChain.java:38)
        at com.eed3si9n.jarjar.JJProcessor.process(JJProcessor.scala:109)
        at com.eed3si9n.jarjarabrams.Shader$.$anonfun$bytecodeShader$6(Shader.scala:118)
        at com.eed3si9n.jarjarabrams.Shader$.$anonfun$shadeFile$1(Shader.scala:21)
        at com.eed3si9n.jarjarabrams.Zip$.$anonfun$transformJarFile$4(Zip.scala:83)
        at scala.collection.parallel.AugmentedIterableIterator.flatmap2combiner(RemainsIterator.scala:133)
        at scala.collection.parallel.AugmentedIterableIterator.flatmap2combiner$(RemainsIterator.scala:130)
        at scala.collection.parallel.immutable.ParVector$ParVectorIterator.flatmap2combiner(ParVector.scala:66)
        at scala.collection.parallel.ParIterableLike$FlatMap.leaf(ParIterableLike.scala:1082)
        at scala.collection.parallel.Task.$anonfun$tryLeaf$1(Tasks.scala:53)
        at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
        at scala.util.control.Breaks$$anon$1.catchBreak(Breaks.scala:67)
        at scala.collection.parallel.Task.tryLeaf(Tasks.scala:56)
        at scala.collection.parallel.Task.tryLeaf$(Tasks.scala:50)
        at scala.collection.parallel.ParIterableLike$FlatMap.tryLeaf(ParIterableLike.scala:1078)
        at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask.internal(Tasks.scala:160)
        at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask.internal$(Tasks.scala:157)
        at scala.collection.parallel.AdaptiveWorkStealingForkJoinTasks$WrappedTask.internal(Tasks.scala:440)
        at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask.compute(Tasks.scala:150)
        at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask.compute$(Tasks.scala:149)
        at scala.collection.parallel.AdaptiveWorkStealingForkJoinTasks$WrappedTask.compute(Tasks.scala:440)
        at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
        at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
        at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
        at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
        at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
        at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

The only possible way that the backing map for a HashSet can be null is if it is accessed before its init updates the map reference. To fix this, I have simply wrapped the assignment and accesses of currentDependenciesSet using a Mutex. (This error was surfaced from the logging changes as well.)

Let me know if you would like anything changed!

@eed3si9n
Copy link
Copy Markdown
Owner

Thanks!

@eed3si9n eed3si9n merged commit 7cf8bd8 into eed3si9n:develop Jan 20, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants