Audit date: 2026-07-08. Scope: library code under src/ (excluding src/test/**,
serialization_test.rs, examples/**, and #[cfg(test)] modules).
These methods are not implemented. Each is marked #[deprecated(note = "placeholder only; will panic if called")] and calls unreachable!(...) if invoked. Doc comments state they are placeholders.
| Location | Method |
|---|---|
dds/with_key/datawriter.rs |
get_matched_subscriptions() |
dds/with_key/datareader.rs |
wait_for_historical_data() |
dds/pubsub.rs |
Publisher::suspend_publications() |
dds/pubsub.rs |
Publisher::resume_publications() |
dds/pubsub.rs |
Publisher::wait_for_acknowledgments() |
ParticipantAccessControl::set_listener now returns Err(...) like the authentication plugin (no panic).
Several panic! sites now prefix the message with "RustDDS internal bug:" so a crash clearly indicates a library defect, not user misuse. See commits touching rtps/reader.rs, rtps/writer.rs, discovery/discovery_db.rs, dds/participant.rs, dds/pubsub.rs, security/security_plugins.rs, dds/with_key/simpledatareader.rs, dds/with_key/datasample_cache.rs.
- Duplicate receive timestamp in
datasample_cachelogserror!and overwrites instead of panicking.
Still present inside block comments; no runtime effect:
DataWriter::{get_liveliness_lost_status, get_offered_incompatible_qos_status, get_publication_matched_status}indatawriter.rsSubscriber::lookup_datareaderinpubsub.rsTopic::get_inconsistent_topic_statusintopic.rs
Category D — fragment bounds (network input)
data_frag.rs: rejectfragmentsInSubmessage < 1, fragment span overflow, span beyondexpected_total, and oversized payload vs claimed fragment run.fragment_assembler.rs:AssemblyBuffer::newandinsert_fragsreturnOption/bool; invalid spans log and skip instead of panicking onBitVec::set.- Unit tests:
data_frag::tests::*,fragment_assembler::tests::reject_fragment_span_beyond_total,fragment_assembler_rejects_span_beyond_total.
Category C — startup / lifecycle
discovery.rs:construct_topic_and_pollusestry_construct!; discovery start handshake logs and returns instead of.expect().dp_event_loop.rs:DPEventLoop::new→CreateResult<Self>; runtimepoll()failure breaks loop cleanly.participant.rs: dp_event_loop ready handshake before returningDomainParticipantInner; discoveryjoin()warns on panic instead of unwrap.udp_listener.rs:new_socketpropagates non-blocking / mio errors with?.secure_discovery.rs: missing Property QoS returnsSecurityResult::Err(surfaces viatry_construct!in discovery).
Still open in Category C: secure_discovery.rs:2639 .expect on missing local participant data (internal state bug).
Category D — send-path serialization
writer.rssend_message_to_readers:write_to_vec_fastfailure logs and skips send.reader.rsencode_and_send: same for reader-originated messages.message.rs:try_submessage_content_length; related sample identity serialize errors log and skip submessage;data_size/sample_sizechecked conversions; nocontent_length as u16truncation.writer.rsfragment iterator:u32::try_from(data_size)instead of unwrap.rtps_reader_proxy.rs:mark_all_frags_requesteduses checkedusize::try_from.serialized_payload.rs: infallibleFrom<SerializedPayload> for Bytes(manual header concat).
Category F — public API documentation and footguns
Sample::unwrap: deprecated; usevalue()or match on variants.pubsub.rs:unwrap_or_new_entity_idreturnsCreateResult(no panic when participant dropped).# Panicsrustdoc on placeholder APIs,Publisher,Subscriber,DomainParticipant,Sample::unwrap,AsyncWrite.
These indicate a RustDDS logic error. Messages should stay explicit; no need to return Result unless recovery is meaningful.
| Item | File / area | Trigger | Notes |
|---|---|---|---|
| Topic name ≠ topic cache name | rtps/reader.rs |
Mismatched ReaderIngredients |
Message updated |
| Stateless + Reliable reader/writer | rtps/reader.rs, rtps/writer.rs |
Internal like_stateless + Reliable QoS |
Public API passes false; only internal misuse |
with_mutable_writer_proxy re-insert |
rtps/reader.rs |
Worker closure violates contract | Message updated |
| Poisoned topic cache mutex | rtps/reader.rs, simpledatareader.rs |
Prior panic while holding lock | Message updated |
| Poisoned DiscoveryDB RwLock | discovery/discovery_db.rs, participant.rs |
Prior panic | Message updated |
| Poisoned InnerPublisher mutex | dds/pubsub.rs |
Prior panic | Message updated |
| Poisoned SecurityPlugins mutex | security/security_plugins.rs |
Prior panic | Message updated |
| Instance disappeared between select and access | datasample_cache.rs |
Cache inconsistency | Message updated |
| SPDP built-in entity id assert | discovery/spdp_participant_data.rs |
Non-built-in id passed to proxy helper | Debug build only (assert!) |
DisposeByKeyHash in DATA_FRAG flags |
rtps/message.rs |
Internal message build bug | unreachable!(); data_frag_msg returns early for this variant |
Widespread pattern: .lock().unwrap(), .read().unwrap(), .write().unwrap() on:
DomainParticipantinner (dpi)WriterSendBuffer+ condvar waitsDDSCache/ topic caches- Status channels (
statusevents.rs,mio_source.rswithmio_08) - ROS 2 node inner mutex
Todo: Prefer lock()/read()/write() match arms that log and abort gracefully, or propagate poison as Err on public APIs. Low urgency if Category A panics are rare.
Most P1 items addressed — see P1 hardening above. Remaining:
| Item | File | Condition |
|---|---|---|
| Security: local participant data missing from DB | discovery/secure_discovery.rs:2639 |
Internal discovery state bug |
Fragment bounds (P1) and send-path serialization (P2) done. No remaining P2 items.
| Item | File | Notes |
|---|---|---|
Timestamp + Duration |
structure/time.rs:147 |
Plain u64 add; wraps near 2106; debug may panic |
NumberSet deserialize |
structure/sequence_number.rs |
Rejects num_bits > 256 with error (good) |
| Release builds | crate-wide | No #![deny(arithmetic_overflow)]; unsigned ops wrap |
Todo: Use checked_add / saturating_add in Timestamp + Duration or document wrap as intentional RTPS semantics.
Most P2 items addressed — see P2 hardening above. Remaining:
| Item | File | Mitigation |
|---|---|---|
AsyncWrite timeout sample.take().unwrap() |
datawriter.rs |
Internal invariant; documented on AsyncWrite |
- Test helpers in
network/udp_sender.rs,network/udp_listener.rs rtps/message.rstest module panicsdiscovery/sedp_messages.rstestpanic!()
P1: Category D fragment bounds validation (network input)DoneP1: Category C discovery/participant startupDone (except secure_discovery internalexpect→Result.expect)P2: Category D send-path serialization unwrap → log + dropDoneP2: Category F public API panic documentationDone- P3: Category B poison handling strategy (project-wide policy)
- P3: Category E timestamp arithmetic