Skip to content

Fix crashes in Clojure-related hooks: NPE on nil var root and CCE in traceGenericCmp - #1065

Open
just-sultanov wants to merge 2 commits into
CodeIntelligenceTesting:mainfrom
just-sultanov:fix/clojure-fuzzing-crashes
Open

Fix crashes in Clojure-related hooks: NPE on nil var root and CCE in traceGenericCmp#1065
just-sultanov wants to merge 2 commits into
CodeIntelligenceTesting:mainfrom
just-sultanov:fix/clojure-fuzzing-crashes

Conversation

@just-sultanov

Copy link
Copy Markdown

Summary

Two fixes for crashes in built-in hooks discovered while fuzzing Clojure projects.
In both cases the exception is thrown from inside the fuzz target's class loading (ExceptionInInitializerError) and aborts fuzzing before any iteration runs.

1. NPE in ClojureLangHooks.clojureMarkContains on nil var root

The AFTER hook on clojure.lang.Var.getRawRoot dereferenced the hook result without a null check. Reading a non-dynamic var with a nil root (e.g.(def ^:private bb? (System/getProperty "babashka.version")) in riddley 0.2.2, pulled in transitively by manifold -> potemkin -> riddley) passes result = null into the hook, throwing an NPE.

Skip the contains check when the result is null.

2. ClassCastException in TraceCmpHooks.mapHookInternal / setHookInternal

Bracketing keys/elements are found via compareTo, which can succeed across incompatible Number implementations (e.g. clojure.lang.Ratio vs. java.lang.Double in a sorted map). The unboxing in traceGenericCmp requires both operands to have the same runtime class and otherwise throws a ClassCastException.

Only trace comparisons when the bracketing key/element has the same runtime class as the lookup key/element.

Testing

  • Added regression tests: ClojureLangHooksTest and TraceCmpHooksTest.
  • Both tests fail on main and pass with the fix.

The AFTER hook on clojure.lang.Var.getRawRoot dereferenced the result without a null check,
throwing a NullPointerException for non-dynamic vars with a nil root (e.g. riddley 0.2.2)
and aborting fuzzing during target class loading.

Skip the contains check when the result is null and add a regression test.
mapHookInternal and setHookInternal find bracketing keys/elements via compareTo, which can succeed
across incompatible Number implementations (e.g. clojure.lang.Ratio vs. java.lang.Double).
The unboxing in traceGenericCmp requires both operands to have the same runtime class and otherwise
throws a ClassCastException.

Only trace comparisons when the bracketing key/element has the same class as the lookup key and add regression tests.
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.

1 participant