@@ -37,6 +37,15 @@ void AssertNoException(JNIEnv &env) {
3737 _Exit (1 );
3838 }
3939}
40+
41+ // Tracks a registered PC table batch so we can update PCFlags later.
42+ struct PCTableBatch {
43+ uintptr_t pc_base;
44+ std::size_t count;
45+ jazzer::PCTableEntry *entries;
46+ };
47+
48+ std::vector<PCTableBatch> gCoveragePCBatches ;
4049} // namespace
4150
4251namespace jazzer {
@@ -45,24 +54,27 @@ uint8_t *CountersTracker::coverage_counters_ = nullptr;
4554uint8_t *CountersTracker::extra_counters_ = nullptr ;
4655std::mutex CountersTracker::mutex_;
4756
48- void CountersTracker::RegisterCounterRange (uint8_t *start, uint8_t *end) {
57+ void CountersTracker::RegisterCounterRange (uint8_t *start, uint8_t *end,
58+ uintptr_t pc_base,
59+ bool track_batch) {
4960 if (start >= end) {
5061 return ;
5162 }
5263
5364 std::size_t num_counters = end - start;
5465
55- // libFuzzer requires an array containing the instruction addresses associated
56- // with the coverage counters. Since these may be synthetic counters (not
57- // associated with real code), we create PC entries with the flag set to 0 to
58- // indicate they are not real PCs. The PC value is set to the counter index
59- // for identification purposes.
66+ // libFuzzer pairs each 8-bit counter with a PC table entry. We assign
67+ // globally unique synthetic PCs so the symbolizer can resolve them back
68+ // to Java source locations.
6069 PCTableEntry *pc_entries = new PCTableEntry[num_counters];
6170 for (std::size_t i = 0 ; i < num_counters; ++i) {
62- pc_entries[i] = {i, 0 };
71+ pc_entries[i] = {pc_base + i, 0 };
6372 }
6473
6574 std::lock_guard<std::mutex> lock (mutex_);
75+ if (track_batch) {
76+ gCoveragePCBatches .push_back ({pc_base, num_counters, pc_entries});
77+ }
6678 __sanitizer_cov_8bit_counters_init (start, end);
6779 __sanitizer_cov_pcs_init (
6880 reinterpret_cast <uintptr_t *>(pc_entries),
@@ -94,8 +106,12 @@ void CountersTracker::RegisterNewCounters(JNIEnv &env, jint old_num_counters,
94106 << std::endl;
95107 _Exit (1 );
96108 }
109+ // Coverage counters use the global edge ID as the PC value and
110+ // track the batch so SetCoveragePCFlags can update entries later.
97111 RegisterCounterRange (coverage_counters_ + old_num_counters,
98- coverage_counters_ + new_num_counters);
112+ coverage_counters_ + new_num_counters,
113+ static_cast <uintptr_t >(old_num_counters),
114+ /* track_batch=*/ true );
99115}
100116
101117void CountersTracker::InitializeExtra (JNIEnv &env, jlong counters) {
@@ -123,8 +139,21 @@ void CountersTracker::RegisterExtraCounters(JNIEnv &env, jint start_offset,
123139 << std::endl;
124140 _Exit (1 );
125141 }
142+ // Extra counters use a disjoint PC range so the symbolizer can tell them
143+ // apart from coverage counters.
126144 RegisterCounterRange (extra_counters_ + start_offset,
127- extra_counters_ + end_offset);
145+ extra_counters_ + end_offset,
146+ kExtraCountersPCBase + start_offset);
147+ }
148+
149+ void CountersTracker::SetCoveragePCFlags (std::size_t edge_id, uintptr_t flags) {
150+ std::lock_guard<std::mutex> lock (mutex_);
151+ for (auto &batch : gCoveragePCBatches ) {
152+ if (edge_id >= batch.pc_base && edge_id < batch.pc_base + batch.count ) {
153+ batch.entries [edge_id - batch.pc_base ].PCFlags |= flags;
154+ return ;
155+ }
156+ }
128157}
129158
130159} // namespace jazzer
@@ -149,13 +178,22 @@ Java_com_code_1intelligence_jazzer_runtime_CoverageMap_getEverCoveredIds(
149178 JNIEnv *env, jclass) {
150179 uintptr_t *covered_pcs;
151180 jint num_covered_pcs = __sanitizer_cov_get_observed_pcs (&covered_pcs);
152- std::vector<jint> covered_edge_ids (covered_pcs,
153- covered_pcs + num_covered_pcs);
181+
182+ // Filter out extra-counter PCs (>= kExtraCountersPCBase) which would
183+ // overflow jint and corrupt Java-side coverage analysis.
184+ std::vector<jint> covered_edge_ids;
185+ covered_edge_ids.reserve (num_covered_pcs);
186+ for (jint i = 0 ; i < num_covered_pcs; ++i) {
187+ if (covered_pcs[i] < jazzer::kExtraCountersPCBase ) {
188+ covered_edge_ids.push_back (static_cast <jint>(covered_pcs[i]));
189+ }
190+ }
154191 delete[] covered_pcs;
155192
156- jintArray covered_edge_ids_jni = env->NewIntArray (num_covered_pcs);
193+ jint count = static_cast <jint>(covered_edge_ids.size ());
194+ jintArray covered_edge_ids_jni = env->NewIntArray (count);
157195 AssertNoException (*env);
158- env->SetIntArrayRegion (covered_edge_ids_jni, 0 , num_covered_pcs ,
196+ env->SetIntArrayRegion (covered_edge_ids_jni, 0 , count ,
159197 covered_edge_ids.data ());
160198 AssertNoException (*env);
161199 return covered_edge_ids_jni;
0 commit comments