1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

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<float> 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
This commit is contained in:
Udit Jain
2026-07-24 04:51:45 +05:30
parent 0e09f1a238
commit c8446af29a
2 changed files with 19 additions and 1 deletions
@@ -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<float> descriptors;
ASSERT_NO_THROW(hog.compute(src, descriptors));
EXPECT_FALSE(descriptors.empty());
}
}} // namespace