From 4d1886354534f0795411721b829f2d28a7d8b976 Mon Sep 17 00:00:00 2001 From: Peter Samarin Date: Wed, 5 Nov 2025 17:14:45 +0100 Subject: [PATCH] fix: instrumention of nested records, and records with annotated fields Using ClassWriter without ClassReader in asm, seems to produce corrupted bytecode for nested records and records with annotated fields. Prior to this fix, a segfault was triggered for nested records that use Jazzer annotations when Jazzer was trying to access data on record components, when trying to create a record mutator. In addition, for non-nested records with annotated fields as for example: record Address(byte @WithLength(max=10) [] data) {} no suitable mutator could be found. --- .../instrumentor/TraceDataFlowInstrumentor.kt | 2 +- tests/BUILD.bazel | 29 ++++++++++++++ .../java/com/example/NestedRecordFuzzer.java | 39 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/src/test/java/com/example/NestedRecordFuzzer.java diff --git a/src/main/java/com/code_intelligence/jazzer/instrumentor/TraceDataFlowInstrumentor.kt b/src/main/java/com/code_intelligence/jazzer/instrumentor/TraceDataFlowInstrumentor.kt index e637e9515..d4399c6a8 100644 --- a/src/main/java/com/code_intelligence/jazzer/instrumentor/TraceDataFlowInstrumentor.kt +++ b/src/main/java/com/code_intelligence/jazzer/instrumentor/TraceDataFlowInstrumentor.kt @@ -52,7 +52,7 @@ internal class TraceDataFlowInstrumentor( } } - val writer = ClassWriter(ClassWriter.COMPUTE_MAXS) + val writer = ClassWriter(reader, ClassWriter.COMPUTE_MAXS) node.accept(writer) return writer.toByteArray() } diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index 7b4290d60..7289f9d3a 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -1077,6 +1077,35 @@ java_fuzz_target_test( ], ) +java_fuzz_target_test( + name = "NestedRecordFuzzer", + timeout = "short", + srcs = [ + "src/test/java/com/example/NestedRecordFuzzer.java", + ], + fuzzer_args = [ + "-print_final_stats=1", + "-runs=10000", + ], + javacopts = [ + "--release", + "17", + ], + tags = [ + "no-jdk8", + ], + target_class = "com.example.NestedRecordFuzzer", + runtime_deps = [ + "@maven//:org_junit_jupiter_junit_jupiter_engine", + ], + deps = [ + "//deploy:jazzer-junit", + "//deploy:jazzer-project", + "@maven//:org_junit_jupiter_junit_jupiter_api", + "@maven//:org_junit_jupiter_junit_jupiter_params", + ], +) + java_fuzz_target_test( name = "BigDecimalFuzzer", srcs = [ diff --git a/tests/src/test/java/com/example/NestedRecordFuzzer.java b/tests/src/test/java/com/example/NestedRecordFuzzer.java new file mode 100644 index 000000000..5027fc98a --- /dev/null +++ b/tests/src/test/java/com/example/NestedRecordFuzzer.java @@ -0,0 +1,39 @@ +/* + * Copyright 2024 Code Intelligence GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example; + +import com.code_intelligence.jazzer.junit.FuzzTest; +import com.code_intelligence.jazzer.mutation.annotation.NotNull; +import com.code_intelligence.jazzer.mutation.annotation.WithLength; + +/** + * This regression test checks if we instrument fuzz test classes with nested records correctly, and + * can start a fuzzing run at all without getting segfaults. + */ +public class NestedRecordFuzzer { + record Address(@NotNull String street, byte @NotNull @WithLength(min = 3, max = 4) [] data) {} + + @FuzzTest + public void test(Address address) { + if (address != null) { + byte[] data = address.data(); + if (data.length < 3 || data.length > 4) { + throw new IllegalStateException("Data length out of bounds: " + data.length); + } + } + } +}