From c8446af29a7d2012484031a384690f24d764599f Mon Sep 17 00:00:00 2001 From: Udit Jain Date: Fri, 24 Jul 2026 04:51:45 +0530 Subject: [PATCH] objdetect: fix out-of-bounds write in HOG gaussian weights (blockSize.height vs width) In HOGCache::init the block gaussian weights are computed into two buffers: AutoBuffer di(blockSize.height), dj(blockSize.width); The vectorized (CV_SIMD128) loop that fills dj was bounded by `blockSize.height` instead of `blockSize.width`. When the block is taller than it is wide, `v_store(_dj + j, ...)` writes past the end of the width-sized dj buffer, causing a heap buffer overflow / access violation (e.g. HOGDescriptor with a 198x281 window, or the 2399x2400 case from the report). Bound the dj loop by `blockSize.width` to match the buffer size and the scalar tail loop. This keeps the SIMD path (unlike the workaround in the report, which disabled it). Added a regression test that computes a HOGDescriptor with a tall block; without the fix it triggers a heap-buffer-overflow (confirmed with AddressSanitizer at hog.cpp:731 inside HOGCache::init). Fixes #23580 --- modules/objdetect/src/hog.cpp | 2 +- modules/objdetect/test/test_cascadeandhog.cpp | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/modules/objdetect/src/hog.cpp b/modules/objdetect/src/hog.cpp index 1c7c8f73cb..7194b068ff 100644 --- a/modules/objdetect/src/hog.cpp +++ b/modules/objdetect/src/hog.cpp @@ -723,7 +723,7 @@ void HOGCache::init(const HOGDescriptor* _descriptor, #if CV_SIMD128 idx = v_float32x4(0.0f, 1.0f, 2.0f, 3.0f); - for (; j <= blockSize.height - 4; j += 4) + for (; j <= blockSize.width - 4; j += 4) { v_float32x4 t = v_sub(idx, _bw); t = v_mul(t, t); diff --git a/modules/objdetect/test/test_cascadeandhog.cpp b/modules/objdetect/test/test_cascadeandhog.cpp index 08c78f8ae5..ddec0e7b25 100644 --- a/modules/objdetect/test/test_cascadeandhog.cpp +++ b/modules/objdetect/test/test_cascadeandhog.cpp @@ -1364,4 +1364,22 @@ TEST(Objdetect_CascadeDetector, small_img) } } +// See https://github.com/opencv/opencv/issues/23580 +// HOGDescriptor::compute() overflowed the gaussian weights buffer when the block +// was taller than it was wide: the SIMD store loop for the width buffer (_dj) was +// bounded by blockSize.height instead of blockSize.width. The block is chosen wide +// enough that the buffer is heap allocated, so the overflow is a real out-of-bounds +// write. "Done" is simply that compute() runs without crashing. +TEST(Objdetect_HOGDescriptor, issue_23580_tall_block_no_overflow) +{ + Size winSize(272, 2048); // height > width, width > AutoBuffer stack size + HOGDescriptor hog(winSize, /*blockSize*/ winSize, /*blockStride*/ Size(8, 8), + /*cellSize*/ Size(8, 8), /*nbins*/ 9); + + Mat src(winSize, CV_8UC1, Scalar::all(0)); + std::vector descriptors; + ASSERT_NO_THROW(hog.compute(src, descriptors)); + EXPECT_FALSE(descriptors.empty()); +} + }} // namespace