Skip to content

Maximize API#1036

Open
kyakdan wants to merge 9 commits intomainfrom
CIF-1902-maximize
Open

Maximize API#1036
kyakdan wants to merge 9 commits intomainfrom
CIF-1902-maximize

Conversation

@kyakdan
Copy link
Member

@kyakdan kyakdan commented Feb 3, 2026

Summary

Add a hill-climbing maximize() API to Jazzer that guides the fuzzer toward maximizing a value over time. This enables fuzzing scenarios where standard code coverage provides insufficient guidance, such as finding inputs that maximize some computed metric.

Changes

Jazzer.maximize() API

// Guide fuzzer to maximize 'value' within [0, 1023]
Jazzer.maximize(value, id);

// Convenience overload with auto-generated call-site ID (requires instrumentation)
Jazzer.maximize(value);

How it works: For each observed value v, sets coverage counters [0, 1023 - v] to 1. This creates incremental progress feedback - higher values trigger more "coverage," guiding the fuzzer toward the maximum. Corpus minimization naturally retains only the input producing the highest value.

Example

Added ReactorFuzzTest demonstrating the API on a chaotic feedback system where standard coverage is constant but the fuzzer needs to maximize a computed temperature value.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a maximize() API to Jazzer that enables hill-climbing fuzzing scenarios where standard code coverage is insufficient. The API guides the fuzzer to maximize a value by setting coverage counters for all values from the minimum up to the observed value, creating incremental progress feedback.

Changes:

  • Added CountersTracker infrastructure (Java and C++) to manage extra coverage counters separate from regular code coverage
  • Added Jazzer.maximize() API with automatic call-site ID generation via instrumentation hooks
  • Added comprehensive test coverage for the new APIs
  • Added ReactorFuzzTest example demonstrating the maximize API on a chaotic feedback system

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/main/native/com/code_intelligence/jazzer/driver/counters_tracker.h Refactored header from CoverageTracker to CountersTracker, adding support for separate extra counters region
src/main/native/com/code_intelligence/jazzer/driver/counters_tracker.cpp New implementation managing both coverage and extra counters with libFuzzer registration
src/main/native/com/code_intelligence/jazzer/driver/BUILD.bazel Updated build dependencies to reference counters_tracker instead of coverage_tracker
src/main/java/com/code_intelligence/jazzer/runtime/CountersTracker.java New Java class providing thread-safe counter allocation and management API
src/main/java/com/code_intelligence/jazzer/runtime/BUILD.bazel Added CountersTracker build target and dependencies
src/main/java/com/code_intelligence/jazzer/runtime/JazzerApiHooks.java Added instrumentation hook to auto-generate call-site IDs for maximize() calls
src/main/java/com/code_intelligence/jazzer/api/Jazzer.java Added maximize() API methods with documentation
src/test/java/com/code_intelligence/jazzer/runtime/CountersTrackerTest.java Comprehensive unit tests for CountersTracker including concurrency tests
src/test/java/com/code_intelligence/jazzer/api/MaximizeTest.java Unit tests for the maximize() API covering edge cases
examples/junit/src/test/java/com/example/ReactorFuzzTest.java Example demonstrating maximize() on a temperature maximization problem

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@oetr oetr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition, thanks!

@kyakdan kyakdan force-pushed the CIF-1902-maximize branch 3 times, most recently from 9d828d3 to 429b534 Compare February 12, 2026 13:13
CountersTracker provides a flexible API for mapping program state to
coverage counters, enabling incremental progress feedback to libFuzzer.

Key features:
- ensureCountersAllocated(id, numCounters): allocate counter range
- setCounter/setCounterRange: set counter values by ID and offset
- Thread-safe allocation via ConcurrentHashMap
- Separate memory region from main coverage map

This lays the foundation for the maximize() hill-climbing API.
Add Jazzer.maximize(value, id, minValue, maxValue) for guiding the
fuzzer to maximize a value over time. For each observed value v in
[minValue, maxValue], sets counters [0, v-minValue] to signal progress.

Features:
- Enables corpus minimization (only max-value input retained)
- Convenience overload without explicit ID (uses instrumentation hook)
- Delegates to CountersTracker for counter management
- No state in Jazzer.java - all managed by CountersTracker
Example shows how maximize() helps fuzz a chaotic feedback system
where standard coverage provides no guidance. The fuzzer is guided
to increase "temperature" through complex state-dependent logic.
Copy link
Contributor

@oetr oetr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM already! Consider auto-mapping to our range--it will make this way easier to use.

* the code under test. When thrown during fuzzing, it stops the current fuzz test with an error
* instead of reporting a bug in the fuzz target.
*/
public class JazzerApiException extends RuntimeException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider making it final, to signal that we do not plan to subclass it and add error hierarchies.

// We need to drive 'temperature' to an extreme value.
// Standard coverage is 100% constant here (it just loops).
long mapped = temperature * 1023 / 4500;
Jazzer.maximize(mapped);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This version forces the users to write mappers every time they use maximize. It's easy to make mistake when writing them. I think we should automatically map the given user range to our range.

I liked the old API version more, it just lacked the mapping to fixed range of IDs, and runtime checks that the parameters stay constant, but it was easier to use.
Consider Jazzer.maximize(value, a, b) --- when the value is between a to b, there will be different coverage (between 0 to 1023), below a nothing, and after b just max coverage.

* <p>The counters are allocated from a dedicated memory region separate from the main coverage map,
* ensuring isolation and preventing interference with regular coverage tracking.
*/
public final class CountersTracker {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming (feel free to ignore): WDYT of renaming to ExtraCountersTracker?

naming (ffti): I also got confused that coverage_tracker.c/cpp (which IMO made sense) got renamed into counters_tracker.c/cpp, but here we still have the CoverageMap.java, which is used all the time by Jazzer, and CountersTracker.java which will rarely be used. Then why is coverage_tracker.cpp (main idea) renamed to counters_tracker.cpp?

int parsed = Integer.parseInt(value.trim());
if (parsed < 0) {
throw new IllegalArgumentException(
ENV_MAX_NUM_COUNTERS + " must not be negative, got: " + parsed);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should probably be greater than INITIAL_NUM_COUNTERS as well.

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