From 3594b48857b5835c5667be152c725384a72965c4 Mon Sep 17 00:00:00 2001 From: Dmitry Ilyin <6576495+widgetii@users.noreply.github.com> Date: Sun, 16 Aug 2026 10:26:17 +0300 Subject: [PATCH 1/2] sensors: serialise getsensor* and stop getsensorid falling through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/sensors.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/sensors.c b/src/sensors.c index 4e96ddd..f4b94ee 100644 --- a/src/sensors.c +++ b/src/sensors.c @@ -1233,10 +1233,13 @@ if (!open_i2c_sensor_fd(i2c_adapter_nr)) } - -} +} + /* All buses probed, nothing answered. Without this the function fell off + * the end (UB): the bool came back indeterminate — often true — and the + * caller then formatted an uninitialised ctx into a garbage name. */ + return false; } #ifndef STANDALONE_LIBRARY @@ -1275,20 +1278,36 @@ cJSON *detect_sensors() { #endif +/* getsensorid() drives i2c detection through the process-global i2c_adapter_nr + * and both entry points below format into one shared sensor_indentity buffer, + * none of it locked. Two threads calling these at once stomp the adapter number + * mid-probe (wrong bus -> detection fails -> garbage) and tear the buffer write. + * Serialise the whole detect-and-format so every returned value is one complete, + * valid string. */ +static pthread_mutex_t sensor_indentity_mtx = PTHREAD_MUTEX_INITIALIZER; static char sensor_indentity[16]; const char *getsensoridentity() { + pthread_mutex_lock(&sensor_indentity_mtx); sensor_ctx_t ctx; - if (!getsensorid(&ctx)) - return NULL; - lsnprintf(sensor_indentity, sizeof(sensor_indentity), "%s_%s", - ctx.sensor_id, ctx.control); - return sensor_indentity; + const char *ret = NULL; + if (getsensorid(&ctx)) { + lsnprintf(sensor_indentity, sizeof(sensor_indentity), "%s_%s", + ctx.sensor_id, ctx.control); + ret = sensor_indentity; + } + pthread_mutex_unlock(&sensor_indentity_mtx); + return ret; } const char *getsensorshort() { + pthread_mutex_lock(&sensor_indentity_mtx); sensor_ctx_t ctx; - if (!getsensorid(&ctx)) - return NULL; - lsnprintf(sensor_indentity, sizeof(sensor_indentity), "%s", ctx.sensor_id); - return sensor_indentity; + const char *ret = NULL; + if (getsensorid(&ctx)) { + lsnprintf(sensor_indentity, sizeof(sensor_indentity), "%s", + ctx.sensor_id); + ret = sensor_indentity; + } + pthread_mutex_unlock(&sensor_indentity_mtx); + return ret; } From 14d3744d694e53d4baae696b729f9c0683f86bbf Mon Sep 17 00:00:00 2001 From: Dmitry Ilyin <6576495+widgetii@users.noreply.github.com> Date: Sun, 16 Aug 2026 11:05:53 +0300 Subject: [PATCH 2/2] build: link Threads for the sensor-detection mutex 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. --- CMakeLists.txt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b9f2f14..aff50df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,11 @@ project(ipctool C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_FLAGS "-std=gnu99") +# sensors.c serialises sensor detection with a pthread mutex. On musl and +# glibc >= 2.34 the pthread symbols live in libc, but older glibc and uClibc +# need the explicit link flag, so ask for it rather than rely on the toolchain. +find_package(Threads REQUIRED) + cmake_policy(SET CMP0069 NEW) if(NOT BUILD_SHARED_LIBS) @@ -181,13 +186,15 @@ set(CYAML_TEST_SRC add_library(ipchw STATIC ${COMMON_LIB_SRC}) target_compile_definitions(ipchw PUBLIC STANDALONE_LIBRARY ${IPCHW_VENDOR_DEFS}) -target_link_libraries(ipchw m) +# Threads is carried on the interface so anything linking this static library +# (ipcinfo here, and external consumers of libipchw) pulls pthread in too. +target_link_libraries(ipchw m Threads::Threads) if(NOT ONLY_LIBRARY) add_executable(ipctool ${IPCTOOL_SRC} ${COMMON_LIB_SRC_ALL}) target_compile_definitions(ipctool PRIVATE ${IPCHW_ALL_VENDOR_DEFS}) - target_link_libraries(ipctool m) + target_link_libraries(ipctool m Threads::Threads) install(TARGETS ipctool RUNTIME DESTINATION /usr/bin/) add_executable(ipcinfo example/ipcinfo.c src/tools.c ${VERSION_SRC})