|
| 1 | +#![no_main] |
| 2 | + |
| 3 | +use arbitrary::{Arbitrary, Unstructured}; |
| 4 | +use libfuzzer_sys::fuzz_target; |
| 5 | +use rustworkx_core::dictmap::DictMap; |
| 6 | +use rustworkx_core::petgraph::graph::Graph; |
| 7 | +use rustworkx_core::petgraph::prelude::*; |
| 8 | +use rustworkx_core::petgraph::Undirected; |
| 9 | +use rustworkx_core::shortest_path::dijkstra; |
| 10 | +use rustworkx_core::Result; |
| 11 | + |
| 12 | +#[derive(Debug, Arbitrary)] |
| 13 | +struct FuzzGraph { |
| 14 | + edges: Vec<(usize, usize, usize)>, |
| 15 | + node_count: usize, |
| 16 | +} |
| 17 | + |
| 18 | +fuzz_target!(|data: &[u8]| { |
| 19 | + if let Ok(fuzz_input) = FuzzGraph::arbitrary(&mut Unstructured::new(data)) { |
| 20 | + fuzz_check_dijkstra_triangle_inequality(&fuzz_input); |
| 21 | + } |
| 22 | +}); |
| 23 | + |
| 24 | +fn fuzz_check_dijkstra_triangle_inequality(input: &FuzzGraph) { |
| 25 | + if input.node_count == 0 |
| 26 | + || input.edges.is_empty() |
| 27 | + || input.node_count > 1000 |
| 28 | + || input.edges.len() > 10_000 |
| 29 | + { |
| 30 | + return; |
| 31 | + } |
| 32 | + let mut graph = Graph::<(), usize, Undirected>::new_undirected(); |
| 33 | + let mut nodes = Vec::with_capacity(input.node_count); |
| 34 | + for _ in 0..input.node_count { |
| 35 | + nodes.push(graph.add_node(())); |
| 36 | + } |
| 37 | + |
| 38 | + for &(u, v, w) in &input.edges { |
| 39 | + if u < input.node_count && v < input.node_count && w > 0 { |
| 40 | + graph.add_edge(nodes[u], nodes[v], w); |
| 41 | + } |
| 42 | + } |
| 43 | + |
| 44 | + let start_node = nodes[0]; |
| 45 | + |
| 46 | + let res: Result<DictMap<NodeIndex, usize>> = |
| 47 | + dijkstra(&graph, start_node, None, |e| Ok(*e.weight()), None); |
| 48 | + |
| 49 | + let dist_map = res.unwrap(); |
| 50 | + |
| 51 | + for edge in graph.edge_references() { |
| 52 | + let u = edge.source(); |
| 53 | + let v = edge.target(); |
| 54 | + let w = *edge.weight(); |
| 55 | + |
| 56 | + if let (Some(&du), Some(&dv)) = (dist_map.get(&u), dist_map.get(&v)) { |
| 57 | + if let Some(bound) = du.checked_add(w) { |
| 58 | + assert!( |
| 59 | + dv <= bound, |
| 60 | + "Triangle inequality failed: dist[{v:?}] = {dv}, dist[{u:?}] = {du}, w = {w}" |
| 61 | + ); |
| 62 | + } |
| 63 | + |
| 64 | + if let Some(bound) = dv.checked_add(w) { |
| 65 | + assert!( |
| 66 | + du <= bound, |
| 67 | + "Triangle inequality failed: dist[{u:?}] = {du}, dist[{v:?}] = {dv}, w = {w}" |
| 68 | + ); |
| 69 | + } |
| 70 | + } |
| 71 | + } |
| 72 | +} |
0 commit comments