Skip to content

Fix overflow for permanent peer address TTL#343

Open
alienx5499 wants to merge 1 commit intolibp2p:masterfrom
alienx5499:fix-281-permanent-ttl
Open

Fix overflow for permanent peer address TTL#343
alienx5499 wants to merge 1 commit intolibp2p:masterfrom
alienx5499:fix-281-permanent-ttl

Conversation

@alienx5499
Copy link
Contributor

@alienx5499 alienx5499 commented Feb 28, 2026

Summary

Fix undefined behaviour in InmemAddressRepository::calculateExpirationTime when using peer::ttl::kPermanent by mapping permanent TTLs directly to Clock::time_point::max() and adding a regression test.

Details

  • Issue: Signed overflow in InmemAddressRepository::upsertAddresses (GitHub issue #281).
  • Root cause: calculateExpirationTime used max_time - ttl and now + ttl; for ttl::kPermanent == std::chrono::milliseconds::max() both operations can overflow the underlying duration type and trigger UBSAN.
  • Fix:
    • Special‑case ttl::kPermanent in calculateExpirationTime and immediately return Clock::time_point::max().
    • Keep the previous logic (now >= max_time - ttl ? max_time : now + ttl) for all other TTL values.

Tests

  • New regression test: InmemAddressRepository_Test.PermanentTtlNoOverflow in test/libp2p/peer/address_repository/inmem_address_repository_test.cpp, which:
    • Inserts addresses with ttl::kPermanent via addAddresses and upsertAddresses.
    • Verifies they remain after collectGarbage() (permanent TTL addresses should never expire).
  • Additional boundary test: InmemAddressRepository_Test.LargeTtlClampedToMax, which:
    • Uses a TTL very close to Milliseconds::max() and ensures the address remains after collectGarbage().
  • UBSAN build (-DUBSAN=ON) on macOS:
    • Before the fix, a dedicated repro test produced a runtime error: signed integer overflow in libc++ chrono with a frame in InmemAddressRepository::calculateExpirationTime.
    • After the fix, PermanentTtlNoOverflow passes under UBSAN with no reports.
  • Non‑sanitizer build:
    • ctest in build (all 67 tests passed).

Design note

An alternative would be to clamp large TTLs to max_time while still doing duration arithmetic. This change instead maps ttl::kPermanent directly to time_point::max() and leaves the existing logic for other TTLs unchanged, avoiding overflow in the sentinel case while keeping the fix minimal. A separate follow‑up issue proposes modeling permanence explicitly (e.g. a Permanent | ExpiresAt(time_point) style representation) to eliminate this class of bugs long‑term.

Screenshot

The PR includes a UBSAN screenshot taken from build-ubsan showing:

  • The command:
    • UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./test_bin/libp2p_inmem_address_repository_test --gtest_filter="*ReproduceKPermanentUBSAN*" (before the fix).
  • The runtime error: signed integer overflow message.
  • The stack frame pointing to InmemAddressRepository::calculateExpirationTime and the repro test.

Screenshot:

image

Closes #281

@alienx5499 alienx5499 force-pushed the fix-281-permanent-ttl branch from 25d39bc to 409add9 Compare February 28, 2026 10:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Signed overflow in InmemAddressRepository::upsertAddresses

1 participant