Skip to content

Commit 0980f24

Browse files
romanbtomaka
authored andcommitted
Fix possible arithmetic overflow in libp2p-kad. (libp2p#1291)
When the number of active queries exceeds the (internal) JOBS_MAX_QUERIES limit, which is only supposed to bound the number of concurrent queries relating to background jobs, an arithmetic overflow occurs. This is fixed by using saturating subtraction.
1 parent b549a6f commit 0980f24

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

protocols/kad/src/behaviour.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,7 @@ where
13131313
let now = Instant::now();
13141314

13151315
// Calculate the available capacity for queries triggered by background jobs.
1316-
let mut jobs_query_capacity = JOBS_MAX_QUERIES - self.queries.size();
1316+
let mut jobs_query_capacity = JOBS_MAX_QUERIES.saturating_sub(self.queries.size());
13171317

13181318
// Run the periodic provider announcement job.
13191319
if let Some(mut job) = self.add_provider_job.take() {

protocols/kad/src/behaviour/test.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,3 +623,34 @@ fn add_provider() {
623623
QuickCheck::new().tests(3).quickcheck(prop as fn(_,_))
624624
}
625625

626+
/// User code should be able to start queries beyond the internal
627+
/// query limit for background jobs. Originally this even produced an
628+
/// arithmetic overflow, see https://github.com/libp2p/rust-libp2p/issues/1290.
629+
#[test]
630+
fn exceed_jobs_max_queries() {
631+
let (_, mut swarms) = build_nodes(1);
632+
let num = JOBS_MAX_QUERIES + 1;
633+
for _ in 0 .. num {
634+
swarms[0].bootstrap();
635+
}
636+
637+
assert_eq!(swarms[0].queries.size(), num);
638+
639+
current_thread::run(
640+
future::poll_fn(move || {
641+
for _ in 0 .. num {
642+
// There are no other nodes, so the queries finish instantly.
643+
if let Ok(Async::Ready(Some(e))) = swarms[0].poll() {
644+
if let KademliaEvent::BootstrapResult(r) = e {
645+
assert!(r.is_ok(), "Unexpected error")
646+
} else {
647+
panic!("Unexpected event: {:?}", e)
648+
}
649+
} else {
650+
panic!("Expected event")
651+
}
652+
}
653+
Ok(Async::Ready(()))
654+
}))
655+
}
656+

0 commit comments

Comments
 (0)