sensors: make getsensoridentity/getsensorshort thread-safe (fix garbage names under concurrent callers) - #183
Conversation
getsensoridentity()/getsensorshort() drive i2c detection through the global i2c_adapter_nr and format into one shared static buffer, unlocked; getsensorid() also fell off the end with no return when every bus failed. Concurrent callers stomped the adapter mid-probe and tore the buffer, and the missing return let an all-fail probe format an uninitialised ctx — together producing binary-garbage sensor names. Serialise detect+format under one mutex and return false on the exhausted path.
PR Summary by QodoMake sensor identity helpers thread-safe and fix getsensorid() fall-through UB
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo
1.
|
sensors.c now uses pthread_mutex_*, the first real pthread use in the tree, but the targets only linked m. It happens to resolve on musl and glibc >= 2.34 (pthread folded into libc) yet fails to link on older glibc and uClibc. find_package(Threads REQUIRED) and link Threads::Threads on ipchw (interface, so ipcinfo and external consumers of libipchw pull it in) and on ipctool.
|
Addressed — Missing pthread link — fixed. sensors.c's mutex is the first real pthread use in the tree (the other Verified both link paths:
On the approach question your summary raised: agreed the single mutex around detect+format is the minimal-risk fix for the current design. The cleaner long-term shape — drop the global |
The sensor-detection entry points are not thread-safe, and a concurrent caller makes them return a binary-garbage sensor name (e.g.
getsensoridentity()yielding^P\xbf\xbf...instead ofsc2332_i2c). Three defects on the path, none of them locked:getsensorid()drives probing through the process-globali2c_adapter_nrand writes it in its retry loop (i2c_adapter_nr = i;). Two threads probing at once clobber each other's bus number mid-scan, so one probes the wrong adapter and detection fails.getsensorid()falls off the end with noreturnwhen every bus fails — the retryforloop closes and so does the function, with noreturn false. Theboolis then indeterminate (oftentrue), so the caller treats an all-failed probe as success and reads an uninitialisedsensor_ctx_t.getsensoridentity()andgetsensorshort()format into onestatic char sensor_indentity[16]vialsnprintf(avsnprintfplus a second in-placetolowerpass — not atomic). Concurrent calls tear the buffer.Chained: a concurrent caller → wrong-bus probe (1) → all fail → fall through returning
truewith a garbagectx(2) → that garbage is formatted into the shared buffer, torn by the other thread (3) → a binary-garbage identity string.Standalone
ipcinfonever hits this (single process, single thread). It shows up when a program linkslibipchwand calls these from more than one thread — e.g. one thread resolving the sensor at startup while another renders the sensor name on a timer.Fix
Serialise detect-and-format under one mutex in the two public entry points (they call
getsensorid()internally, which does not take the lock, so there's no self-deadlock and directgetsensorid()callers are unaffected), and givegetsensorid()the missingreturn falseon the exhausted-buses path. With the writes serialised, every returned value is one complete, valid string.Verified
Reproduced on an Ingenic T31 (SC2332) by running a second thread calling
getsensoridentity()in a loop while the main thread resolves the sensor, noSENSORenv, 20 starts:pthread.his already included insrc/sensors.c.