From 871faf538637af426e96be8a1a04651372c6b558 Mon Sep 17 00:00:00 2001 From: EylonKrause Date: Tue, 30 Jun 2026 11:56:47 +0300 Subject: [PATCH] x86: size CacheInfo::levels to hold all leaf 2 cache descriptors ParseLeaf2 appends a CacheLevelInfo for every non-zero descriptor byte in CPUID leaf 2 (up to 15, since the AL count byte is ignored) into the fixed CacheInfo::levels[CPU_FEATURES_MAX_CACHE_LEVEL] array. Sized at 10, a CPU reporting more than 10 descriptors overflowed the array; this is reachable from the public GetX86CacheInfo(). Raise CPU_FEATURES_MAX_CACHE_LEVEL from 10 to 16 so the array can hold every descriptor a single leaf 2 can report. This both prevents the overflow and avoids silently dropping cache levels. Add a regression test that feeds 15 descriptors and checks they are all recorded without overflow. --- include/cpu_features_cache_info.h | 7 +++++-- test/cpuinfo_x86_test.cc | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/cpu_features_cache_info.h b/include/cpu_features_cache_info.h index 1a61ee1e..cd0e10e5 100644 --- a/include/cpu_features_cache_info.h +++ b/include/cpu_features_cache_info.h @@ -40,9 +40,12 @@ typedef struct { int partitioning; // number of lines per sector } CacheLevelInfo; -// Increase this value if more cache levels are needed. +// Increase this value if more cache levels are needed. It must be large enough +// to hold every descriptor a single CPUID leaf 2 can report (up to 15, since +// the AL count byte is ignored) so that ParseLeaf2 cannot overflow +// CacheInfo::levels. #ifndef CPU_FEATURES_MAX_CACHE_LEVEL -#define CPU_FEATURES_MAX_CACHE_LEVEL 10 +#define CPU_FEATURES_MAX_CACHE_LEVEL 16 #endif typedef struct { int size; diff --git a/test/cpuinfo_x86_test.cc b/test/cpuinfo_x86_test.cc index 328aa5cf..24e126ae 100644 --- a/test/cpuinfo_x86_test.cc +++ b/test/cpuinfo_x86_test.cc @@ -1399,6 +1399,24 @@ flags : fpu mmx sse sse2 pni ssse3 sse4_1 sse4_2 } // https://www.felixcloutier.com/x86/cpuid#example-3-1--example-of-cache-and-tlb-interpretation +// Regression test: a CPUID leaf 2 advertising the maximum number of cache/TLB +// descriptors must not overflow CacheInfo::levels. +TEST_F(CpuidX86Test, Leaf2_TooManyDescriptors_DoesNotOverflow) { + cpu().SetLeaves({ + {{0x00000000, 0}, Leaf{0x00000002, 0x756E6547, 0x6C65746E, 0x49656E69}}, + {{0x00000001, 0}, Leaf{0x00000F0A, 0x00010808, 0x00000000, 0x3FEBFBFF}}, + // Leaf 2 encodes one descriptor per byte across its four registers (16 + // bytes total). AL, the low byte of EAX, is the ignored count byte, so + // these all-0x01 registers forge 15 non-zero descriptors -- more than the + // old 10-entry CacheInfo::levels array and exactly filling the new 16. + {{0x00000002, 0}, Leaf{0x01010101, 0x01010101, 0x01010101, 0x01010101}}, + }); + + const auto info = GetX86CacheInfo(); + // All 15 descriptors are recorded, saturating the resized levels array. + EXPECT_EQ(info.size, 15); +} + TEST_F(CpuidX86Test, P4_CacheInfo) { cpu().SetLeaves({ {{0x00000000, 0}, Leaf{0x00000002, 0x756E6547, 0x6C65746E, 0x49656E69}},