Skip to content

sensors: close the descriptor getsensorid() opens to test the bus - #185

Merged
widgetii merged 1 commit into
masterfrom
fix/getsensorid-i2c-fd-leak
Aug 31, 2026
Merged

sensors: close the descriptor getsensorid() opens to test the bus#185
widgetii merged 1 commit into
masterfrom
fix/getsensorid-i2c-fd-leak

Conversation

@widgetii

Copy link
Copy Markdown
Member

getsensorid() opens the i2c adapter to find out whether it is there, and then never closes it. The probes it goes on to run open the adapter again and close what they open (get_sensor_id_i2c() ends in close_sensor_fd(fd)), so nothing needs the descriptor taken here — it is a pure leak, one per call, and up to six once the fall-through loop starts sweeping the other adapters.

That is invisible for ipctool itself, which runs once and exits. It is not invisible for a daemon: majestic probes the sensor at every pipeline start and every SIGHUP reload (since #184 and its majestic-side bump), so a camera accumulates one open /dev/i2c-N per reload for the life of the process. Enough of them and open() and accept() start failing process-wide — which presents as a streamer that is still running, still holding its ports, and answering nothing, rather than as a descriptor leak.

Measured

Lab ssc30kq (SigmaStar infinity6e, imx335), majestic master+e2b88b18:

/dev/i2c-1 descriptors held
before, after 26 SIGHUP reloads 29
before, 7 more reloads 36
$SENSOR set so the probe is skipped, 5 reloads 0
after this change, 8 reloads 0

The $SENSOR row is the control: it takes majestic's own path out of the picture and pins the leak on the probe rather than on the vendor SDK.

After the change, total process descriptors are flat at 41→42 across the reloads, Autodetected sensor as 'imx335_i2c' is still logged on every one of them — so each is a genuine probe, not a remembered answer — and the camera keeps answering (/image.jpg 200) throughout a soak of 27 reloads under two steady RTSP pullers, four churning clients, snapshot polling at 0.5 Hz and motion firing every few seconds.

Also

The test becomes fd < 0 rather than !fd. open() reports failure as -1, so the old form read a failed open as success and only the impossible descriptor 0 as failure; the run then fell through to get_sensor_id_i2c(), which opened the adapter properly and failed there instead. Nothing depended on the old spelling.

Deliberately not here

Control flow is otherwise unchanged: the fall-through loop still gives up on the first adapter it cannot open rather than skipping to the next one. Making that sweep actually sweep changes which sensors get detected on which boards, and that does not belong in a leak fix.

`getsensorid()` opens the i2c adapter to find out whether it is there,
and then never closes it. The probes it goes on to run open the adapter
again and close what they open (`get_sensor_id_i2c()` ends in
`close_sensor_fd(fd)`), so nothing needs the descriptor taken here — it
is a pure leak, one per call, and up to six once the fall-through loop
starts sweeping the other adapters.

That is invisible for `ipctool`, which runs once and exits. It is not
invisible for a daemon: majestic probes the sensor at every pipeline
start *and* every SIGHUP reload, so a camera accumulates one open
`/dev/i2c-N` per reload for the life of the process. Enough of them and
`open()` and `accept()` start failing process-wide — which presents as a
streamer that is still running, still holding its ports, and answering
nothing, rather than as a descriptor leak.

Measured on a lab ssc30kq (SigmaStar infinity6e, imx335), majestic
master:

| | `/dev/i2c-1` descriptors held |
|---|---|
| before, 26 reloads | 29 |
| before, 7 more reloads | 36 |
| with `$SENSOR` set, probe skipped, 5 reloads | 0 |
| after this change, 8 reloads | 0 |

The `$SENSOR` row is the control: it takes majestic's own path out of
the picture and pins the leak on the probe.

The test becomes `fd < 0` rather than `!fd`. `open()` reports failure as
-1, so the old form read a failed open as success and only the
impossible descriptor 0 as failure; the run then fell through to
`get_sensor_id_i2c()`, which opened the adapter properly and failed
there instead. No behaviour depended on the old spelling.

Control flow is otherwise unchanged, deliberately: the fall-through loop
still gives up on the first adapter it cannot open rather than skipping
to the next one. Making that sweep actually sweep is a change to what
gets detected, and it does not belong in a leak fix.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Prevent I²C descriptor leaks during sensor detection

🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Closes temporary I²C bus descriptors before sensor probes reopen adapters.
• Correctly treats negative open results as failures without changing adapter-search behavior.
Diagram

sequenceDiagram
    actor Daemon
    participant G as Sensor detection
    participant B as Bus check
    participant A as I2C adapter
    participant P as Sensor probe
    Daemon->>G: Start or reload
    G->>B: Check adapter
    B->>A: Open adapter
    alt Open succeeds
        A-->>B: Descriptor
        B->>A: Close descriptor
        B-->>G: Bus available
        G->>P: Probe sensor
        P->>A: Reopen adapter
        P->>A: Close after probe
    else Open fails
        B-->>G: Bus unavailable
        G-->>Daemon: Detection fails
    end
Loading
High-Level Assessment

The scoped helper is the best approach: it centralizes the temporary descriptor lifecycle across both bus checks, fixes open failure detection, and deliberately preserves sensor-search behavior. Duplicating close calls inline would be less maintainable without changing outcomes.

Files changed (1) +28 / -4

Bug fix (1) +28 / -4
sensors.cClose temporary I²C descriptors during bus availability checks +28/-4

Close temporary I²C descriptors during bus availability checks

• Adds i2c_bus_openable() to open, validate, and immediately close adapters used only for liveness checks. Both initial and fallback adapter paths now use the helper, correctly treating negative descriptors as open failures while preserving existing early-return behavior.

src/sensors.c

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@widgetii
widgetii merged commit c7d8d92 into master Aug 31, 2026
4 checks passed
@widgetii
widgetii deleted the fix/getsensorid-i2c-fd-leak branch August 31, 2026 17:42
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.

1 participant