From 5b40fafe59f5f0b35ecc19b0e3c83561bda51bd8 Mon Sep 17 00:00:00 2001 From: Srijan Upadhyay Date: Wed, 15 Jul 2026 16:44:45 +0530 Subject: [PATCH] linux: treat a negative topology id as unavailable, not a parse error The kernel exposes core_id and physical_package_id as -1 when it has no topology information for a processor. Both were parsed with uint32_parser, which rejects any non-digit lead byte, so every such processor produced an error-level log claiming the sysfs file was malformed: Error in cpuinfo: failed to parse file /sys/devices/system/cpu/cpu0/topology/core_id: "-1" is not an unsigned number -1 is a sentinel, not corruption. Parse it as "value unavailable" via a topology_id_parser wrapper and log it at debug level. The return value is unchanged (false, the id is genuinely unavailable), so no caller behavior changes; only the false alarm goes away. Observed on a native riscv64 board (SiFive U74-class, kernel 5.10.113), which reports core_id -1 on all four cores. physical_package_id parsed fine there, but is exposed to the same sentinel and is covered for consistency. Also fixes uint32_parser's empty-file branch, which hardcoded KERNEL_MAX_FILENAME while the parser is shared by six call sites, so an empty core_id file would have blamed the wrong path. Test Plan: compiled src/linux/processors.c into a harness driving the real static parsers. clang -DCPUINFO_LOG_LEVEL=5 -I src -I include -o t t.c src/log.c before: core_id "-1" -> ok=false + ERROR "is not an unsigned number" after : core_id "-1" -> ok=false + DEBUG "reports no topology information" core_id "0" -> ok=true value=0 core_id "3" -> ok=true value=3 --- src/linux/processors.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/linux/processors.c b/src/linux/processors.c index fd040a3b..eae34a2d 100644 --- a/src/linux/processors.c +++ b/src/linux/processors.c @@ -94,7 +94,7 @@ static const uint32_t default_max_processors_count = CPU_SETSIZE; static bool uint32_parser(const char* filename, const char* text_start, const char* text_end, void* context) { if (text_start == text_end) { - cpuinfo_log_error("failed to parse file %s: file is empty", KERNEL_MAX_FILENAME); + cpuinfo_log_error("failed to parse file %s: file is empty", filename); return false; } @@ -125,6 +125,20 @@ static bool uint32_parser(const char* filename, const char* text_start, const ch return true; } +/* + * The kernel exposes a topology id as -1 when it has no topology information + * for the processor. That is a sentinel rather than a malformed file, so treat + * it as "value unavailable" instead of reporting a parse error for every + * processor. A topology id is never legitimately negative. + */ +static bool topology_id_parser(const char* filename, const char* text_start, const char* text_end, void* context) { + if (text_start != text_end && *text_start == '-') { + cpuinfo_log_debug("file %s reports no topology information for this processor", filename); + return false; + } + return uint32_parser(filename, text_start, text_end, context); +} + uint32_t cpuinfo_linux_get_max_processors_count(void) { uint32_t kernel_max; if (cpuinfo_linux_parse_small_file(KERNEL_MAX_FILENAME, KERNEL_MAX_FILESIZE, uint32_parser, &kernel_max)) { @@ -240,7 +254,7 @@ bool cpuinfo_linux_get_processor_core_id(uint32_t processor, uint32_t core_id_pt } uint32_t core_id; - if (cpuinfo_linux_parse_small_file(core_id_filename, CORE_ID_FILESIZE, uint32_parser, &core_id)) { + if (cpuinfo_linux_parse_small_file(core_id_filename, CORE_ID_FILESIZE, topology_id_parser, &core_id)) { cpuinfo_log_debug( "parsed core id value of %" PRIu32 " for logical processor %" PRIu32 " from %s", core_id, @@ -265,7 +279,7 @@ bool cpuinfo_linux_get_processor_package_id(uint32_t processor, uint32_t package } uint32_t package_id; - if (cpuinfo_linux_parse_small_file(package_id_filename, PACKAGE_ID_FILESIZE, uint32_parser, &package_id)) { + if (cpuinfo_linux_parse_small_file(package_id_filename, PACKAGE_ID_FILESIZE, topology_id_parser, &package_id)) { cpuinfo_log_debug( "parsed package id value of %" PRIu32 " for logical processor %" PRIu32 " from %s", package_id,