{"record":{"id":"41b275fa656b7a6e","repo":"firecracker-microvm/firecracker","slug":"mocked-timer-doesn-t-support-fd","errorCode":null,"errorMessage":"Mocked timer doesn't support fd","messagePattern":"Mocked timer doesn't support fd","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/utils/src/time.rs","lineNumber":328,"sourceCode":"        // SAFETY: Zero init of a PDO type.\n        let mut spec: libc::itimerspec = unsafe { std::mem::zeroed() };\n        // SAFETY: Safe because timerfd_gettime is trusted to only modify `spec`.\n        let ret = unsafe { libc::timerfd_gettime(file.as_raw_fd(), &mut spec) };\n        assert!(\n            0 <= ret,\n            \"TimerFd arm failed: {:#}\",\n            std::io::Error::last_os_error()\n        );\n        spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0\n    }\n}\n\nimpl AsRawFd for TimerFd {\n    fn as_raw_fd(&self) -> RawFd {\n        match self {\n            TimerFd::Real(file) => file.as_raw_fd(),\n            #[cfg(any(test, feature = \"test-utils\"))]\n            TimerFd::Mock(_) => panic!(\"Mocked timer doesn't support fd\"),\n        }\n    }\n}\n\n/// Test-only mock clock and timer, used to make time-based unit tests deterministic.\n///\n/// Gated behind `#[cfg(any(test, feature = \"test-utils\"))]` at the module level so the individual\n/// items don't each need the attribute. Re-exported from the parent so callers keep using\n/// [`MockClock`]/[`MockTimer`] directly.\n#[cfg(any(test, feature = \"test-utils\"))]\nmod mock {\n    use std::sync::{Arc, Mutex};\n    use std::time::{Duration, Instant};\n\n    /// A controllable virtual clock for tests. Starts at the current real time, but only moves\n    /// forward via [`MockClock::advance`]. Cheap to [`Clone`]; all clones share the same\n    /// underlying time, so multiple consumers advance together.\n    #[derive(Debug, Clone)]","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/firecracker-microvm/firecracker/blob/23b09b943fa3cd4a04004fe55724f0b5c2410f45/src/utils/src/time.rs#L310-L346","documentation":"TimerFd is an enum with a Real(file) variant (backed by an actual timerfd) and a Mock(_) variant used only in tests to make time-based tests deterministic. A mocked timer has no kernel file descriptor behind it, so AsRawFd::as_raw_fd cannot return a RawFd and panics with \"Mocked timer doesn't support fd\" instead of returning a Result. This is an intentional, fail-fast misuse guard: any code path that needs a real fd must not run against a mocked clock.","triggerScenarios":"Calling .as_raw_fd() (e.g. to register the timer with epoll/poll) on a TimerFd constructed as TimerFd::Mock, i.e. when the crate is built with the test or test-utils feature (or under cfg(test)) and a mocked clock/timer was injected.","commonSituations":"Running production-style event-loop or polling code in tests with a mocked timer; wiring a TimerFd obtained from a test fixture into an epoll registration helper; accidentally enabling the test-utils feature in a release build so Mock variants exist and get selected.","solutions":["Ensure the code path calling as_raw_fd uses a real timer: construct TimerFd from timerfd_create rather than the mock constructor.","Match on the TimerFd enum before extracting the fd and handle the Mock case explicitly (skip epoll registration or return an error) instead of relying on AsRawFd.","Only enable the test-utils feature in dev-dependencies/test builds, not in release features, so Mock cannot be selected in production.","Restructure tests so time is mocked at a higher level (clock abstraction) while fd-based polling paths use real timers."],"exampleFix":"// before\nlet fd = timer.as_raw_fd(); // panics if TimerFd::Mock\n// after\nlet fd = match timer {\n    TimerFd::Real(f) => f.as_raw_fd(),\n    TimerFd::Mock(_) => return Err(MyError::MockTimerHasNoFd),\n};","handlingStrategy":"type-guard","validationCode":"fn is_real_timer(t: &TimerFd) -> bool { matches!(t, TimerFd::Real(_)) }","typeGuard":"fn as_real_fd(timer: &TimerFd) -> Option<RawFd> {\n    match timer {\n        TimerFd::Real(f) => Some(f.as_raw_fd()),\n        TimerFd::Mock(_) => None,\n    }\n}","tryCatchPattern":"// Rust panics are not catchable via Result; use std::panic::catch_unwind only at boundaries.\nlet fd = match timer { TimerFd::Real(f) => f.as_raw_fd(), TimerFd::Mock(_) => return Err(EpollError::MockTimer) };","preventionTips":["Keep the test-utils feature out of release builds so Mock variants cannot be selected in production paths.","Match on TimerFd before any fd-based API (epoll, poll) instead of blanket-calling as_raw_fd.","Structure tests so polling paths use real timers and only time semantics are mocked.","Add a debug_assert or typed accessor returning Option<RawFd> rather than panicking."],"tags":["rust","timer","testing","file-descriptor"],"backgroundTag":"unsupported-operation","analyzedSha":"23b09b943fa3cd4a04004fe55724f0b5c2410f45","analyzedAt":"2026-09-19T00:01:22.326Z","contentChangedAt":"2026-09-19T00:01:22.326Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}