Repository: AFLplusplus/LibAFL (language: rust)

Issue:
qemu_coverage: Drcov output has non-unique module IDs
**Describe the bug**
The RangeMap struct which is used to track QEMU module ranges coalesces ranges with the same module path. If a smaller range is inserted in the middle of an existing coalesced range, then the outer range is split into two but retains the same ID and path.

In the DRCOV output this will appear as:
```
000, 0xAAAA0000, 0xAAAB0000, 0x0, 0x0, 0x0, "/workspaces/project/libA.so"
001, 0xAAAB0000, 0xAAAC0000, 0x0, 0x0, 0x0, "/workspaces/project/libB.so"
000, 0xAAAC0000, 0xAAAD0000, 0x0, 0x0, 0x0, "/workspaces/project/libA.so"
```
This is illegal and DRCOV consumers will error at the duplicate IDs.

**To Reproduce**
Run qemu_coverage against a target that has one module straddling other module(s).

**Expected behavior**
The DRCOV output should appear as:
```
000, 0xAAAA0000, 0xAAAB0000, 0x0, 0x0, 0x0, "/workspaces/project/libA.so"
001, 0xAAAB0000, 0xAAAC0000, 0x0, 0x0, 0x0, "/workspaces/project/libB.so"
002, 0xAAAC0000, 0xAAAD0000, 0x0, 0x0, 0x0, "/workspaces/project/libA.so"
```



Discussion / hints:

Fix patch:
diff --git a/libafl_qemu/src/modules/drcov.rs b/libafl_qemu/src/modules/drcov.rs
index cd1ca0aa31..989d601666 100644
--- a/libafl_qemu/src/modules/drcov.rs
+++ b/libafl_qemu/src/modules/drcov.rs
@@ -285,7 +285,41 @@ where
                 module_range_map.insert(range, (id, path));
             }
 
-            self.module_mapping = Some(module_range_map);
+            // Split ranges larger than 4GiB into smaller ranges, as Drcov max
+            // module size is 4GiB. This also suffices to give each range a
+            // unique id. (Before this loop, any larger ranges split into many
+            // by smaller ranges retain the same id, which isn't unique.)
+            let mut split_module_range_map: RangeMap<u64, (u16, String)> = RangeMap::new();
+            let mut i = 0;
+            for (range, (_, path)) in module_range_map {
+                let mut range_start = range.start;
+                let range_end = range.end;
+                while range_end - range_start - 1 > u64::from(u32::MAX) {
+                    let range_end_short =
+                        (range_start + u64::from(u32::MAX) + 1) & !u64::from(u32::MAX);
+                    split_module_range_map.insert(
+                        Range {
+                            start: range_start,
+                            end: range_end_short,
+                        },
+                        (i, path.clone()),
+                    );
+                    i += 1;
+                    range_start = range_end_short;
+                }
+                split_module_range_map.insert(
+                    Range {
+                        start: range_start,
+                        end: range_end,
+                    },
+                    (i, path.clone()),
+                );
+                i += 1;
+            }
+
+            self.module_mapping = Some(RangeMap::<u64, (u16, String)>::from_iter(
+                split_module_range_map,
+            ));
         } else {
             log::info!("Using user-provided module mapping for DrCov module.");
         }


Test patch: