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

Compare commits

...

9 Commits

Author SHA1 Message Date
Abhishek Gola 2b6c3df954 Merge pull request #29546 from uwezkhan/dtree-split-index-bound
bound categorical split indices in dtrees readSplit
2026-07-29 13:31:38 +05:30
Abhishek Gola a906dfbed2 Merge pull request #29626 from ArneshBanerjee/fix-29615-icvcvt-pointer-overflow-4x
imgcodecs: fix pointer overflow in 16u icvCvt helpers (4.x)
2026-07-28 19:52:22 +05:30
Arnesh Banerjee b7860407f0 imgcodecs: fix pointer overflow in 16u icvCvt helpers
The 16-bit icvCvt_* helpers in utils.cpp move the row pointer with
step/sizeof(x[0]) - size.width*N. sizeof is unsigned, so this is done in
unsigned math. When the caller passes step == 0, it underflows to a huge
value and the pointer goes out of range, which is undefined behavior.

The TIFF decoder hits this: it walks rows itself and calls these helpers
with step = 0, so reading a 16-bit 4-channel TIFF triggers the bug.

Cast sizeof(...) to int so the math is signed. Same result for normal
calls, no overflow when the step is 0.

Added Imgcodecs_Tiff.regression_29615_16UC4 which round-trips a CV_16UC4
TIFF in memory.

This is the 4.x version of the fix, requested in
https://github.com/opencv/opencv/pull/29620 (issue #29615).
2026-07-28 16:19:17 +05:30
Uwez Khan dee2bb288b bound categorical split indices in dtrees readSplit 2026-07-27 10:54:57 +05:30
Alexander Smorkalov 70fc346580 Merge pull request #29549 from hanu-14:fix-https-readme-md
fix: upgrade http:// to https:// in README.md
2026-07-26 15:02:04 +03:00
Andrei Fedorov 664f59e750 Merge pull request #29542 from intel-staging:ipp/enable_instrumentation_fix
Implemented a check to enable instrumentation for IPP HAL #29542

To enable instrumentation for IPP HAL correctly it needed to generalize a part of `private.hpp` and put it to the separate file that can be included in `private.hpp` and `ipp_utils.hpp` both to avoid duplication.

Built with `-DENABLE_INSTRUMENTATION=ON` and ran `opencv_perf_imgproc --perf_instrument=1`:

  | Test | IPP weight before | IPP weight after |
  |---|---|---|
  | `distanceTransform` (8U->32F) | 0.0% | ~76% |
  | `ippSobel` | 0.0% | ~98% |
  | `scharrViaSobelFilter` | 0.0% | ~90% |

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
2026-07-26 15:01:24 +03:00
Alexander Smorkalov 19ef7e6e16 Merge pull request #29583 from uditjainstjis:fix-23580-hog-buffer-overflow
objdetect: fix out-of-bounds write in HOG gaussian weights #23580 🤖🤖🤖
2026-07-25 10:01:30 +03:00
Udit Jain c8446af29a 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
2026-07-24 04:51:45 +05:30
MOHAMMED HANAN M T P 5ab3e2e580 fix: upgrade http:// to https:// in README.md 2026-07-18 11:13:02 +05:30
11 changed files with 224 additions and 67 deletions
+4 -4
View File
@@ -7,7 +7,7 @@
* Courses: <https://opencv.org/courses>
* Docs: <https://docs.opencv.org/4.x/>
* Q&A forum: <https://forum.opencv.org>
* previous forum (read only): <http://answers.opencv.org>
* previous forum (read only): <https://answers.opencv.org>
* Issue tracking: <https://github.com/opencv/opencv/issues>
* Additional OpenCV functionality: <https://github.com/opencv/opencv_contrib>
* Donate to OpenCV: <https://opencv.org/support/>
@@ -28,9 +28,9 @@ Please read the [contribution guidelines](https://github.com/opencv/opencv/wiki/
### Additional Resources
* [Submit your OpenCV-based project](https://form.jotform.com/233105358823151) for inclusion in Community Friday on opencv.org
* [Subscribe to the OpenCV YouTube Channel](http://youtube.com/@opencvofficial) featuring OpenCV Live, an hour-long streaming show
* [Follow OpenCV on LinkedIn](http://linkedin.com/company/opencv/) for daily posts showing the state-of-the-art in computer vision & AI
* [Subscribe to the OpenCV YouTube Channel](https://youtube.com/@opencvofficial) featuring OpenCV Live, an hour-long streaming show
* [Follow OpenCV on LinkedIn](https://linkedin.com/company/opencv/) for daily posts showing the state-of-the-art in computer vision & AI
* [Apply to be an OpenCV Volunteer](https://form.jotform.com/232745316792159) to help organize events and online campaigns as well as amplify them
* [Follow OpenCV on Mastodon](http://mastodon.social/@opencv) in the Fediverse
* [Follow OpenCV on Mastodon](https://mastodon.social/@opencv) in the Fediverse
* [Follow OpenCV on Twitter](https://twitter.com/opencvlive)
* [OpenCV.ai](https://opencv.ai): Computer Vision and AI development services from the OpenCV team.
+7
View File
@@ -46,6 +46,13 @@ if(WITH_IPP_CALLS_ENFORCED)
message("WITH_IPP_CALLS_ENFORCED=${WITH_IPP_CALLS_ENFORCED}: enforced IPP calls are enabled in IPP HAL")
endif()
# Enable cv::instr tracing of IPP calls inside the HAL so they show up in the
# instrumentation trace / IPP weight. Reuses the engine exported from
# opencv_core (symbols resolved at link time as ipphal is archived into core).
if(ENABLE_INSTRUMENTATION)
target_compile_definitions(ipphal PRIVATE ENABLE_INSTRUMENTATION)
endif()
target_include_directories(ipphal PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-suggest-override)
+16
View File
@@ -1,6 +1,7 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
// Copyright (C) 2026, Intel Corporation, all rights reserved.
#ifndef __IPP_HAL_UTILS_HPP__
#define __IPP_HAL_UTILS_HPP__
@@ -23,7 +24,22 @@
# include "ipp.h"
#endif
// IPP call instrumentation for the standalone IPP HAL.
//
// The HAL is built as a separate static library that does not include the
// internal core/private.hpp, so by default its IPP calls never appear in the
// cv::instr trace (reported IPP weight = 0%). When the parent build enables
// ENABLE_INSTRUMENTATION, the shared instrumentation.private.hpp provides the
// exact same CV_INSTRUMENT_FUN_IPP macro used by core (backed by symbols exported
// from libopencv_core, resolved at link time), so HAL IPP calls are traced
// identically to in-module ones. Otherwise the no-op passthrough is used.
#if !defined(CV_INSTRUMENT_FUN_IPP)
#if defined(ENABLE_INSTRUMENTATION)
#include "opencv2/core/utils/instrumentation.private.hpp"
#else
#define CV_INSTRUMENT_FUN_IPP(FUN, ...) ((FUN)(__VA_ARGS__))
#endif // defined(ENABLE_INSTRUMENTATION)
#endif // !defined(CV_INSTRUMENT_FUN_IPP)
#define CV_HAL_CHECK_USE_IPP() if(!cv::ipp::useIPP()) return CV_HAL_ERROR_NOT_IMPLEMENTED;
+2 -55
View File
@@ -690,23 +690,13 @@ public:
TLSData<InstrTLSStruct> tlsStruct;
};
class CV_EXPORTS IntrumentationRegion
{
public:
IntrumentationRegion(const char* funName, const char* fileName, int lineNum, void *retAddress, bool alwaysExpand, TYPE instrType = TYPE_GENERAL, IMPL implType = IMPL_PLAIN);
~IntrumentationRegion();
private:
bool m_disabled; // region status
uint64 m_regionTicks;
};
CV_EXPORTS InstrStruct& getInstrumentStruct();
InstrTLSStruct& getInstrumentTLSStruct();
CV_EXPORTS InstrNode* getCurrentNode();
}
}
#include "opencv2/core/utils/instrumentation.private.hpp"
#ifdef _WIN32
#define CV_INSTRUMENT_GET_RETURN_ADDRESS _ReturnAddress()
#else
@@ -718,45 +708,6 @@ CV_EXPORTS InstrNode* getCurrentNode();
#define CV_INSTRUMENT_REGION_CUSTOM_META(NAME, ALWAYS_EXPAND, TYPE, IMPL)\
void *CVAUX_CONCAT(__curr_address__, __LINE__) = [&]() {return CV_INSTRUMENT_GET_RETURN_ADDRESS;}();\
::cv::instr::IntrumentationRegion CVAUX_CONCAT(__instr_region__, __LINE__) (NAME, __FILE__, __LINE__, CVAUX_CONCAT(__curr_address__, __LINE__), false, ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN);
// Instrument functions with non-void return type
#define CV_INSTRUMENT_FUN_RT_META(TYPE, IMPL, ERROR_COND, FUN, ...) ([&]()\
{\
if(::cv::instr::useInstrumentation()){\
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL);\
try{\
auto instrStatus = ((FUN)(__VA_ARGS__));\
if(ERROR_COND){\
::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit");\
}\
return instrStatus;\
}catch(...){\
::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit");\
throw;\
}\
}else{\
return ((FUN)(__VA_ARGS__));\
}\
}())
// Instrument functions with void return type
#define CV_INSTRUMENT_FUN_RV_META(TYPE, IMPL, FUN, ...) ([&]()\
{\
if(::cv::instr::useInstrumentation()){\
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL);\
try{\
(FUN)(__VA_ARGS__);\
}catch(...){\
::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
CV_INSTRUMENT_MARK_META(IMPL, #FUN "- BadExit");\
throw;\
}\
}else{\
(FUN)(__VA_ARGS__);\
}\
}())
// Instrumentation information marker
#define CV_INSTRUMENT_MARK_META(IMPL, NAME, ...) {::cv::instr::IntrumentationRegion __instr_mark__(NAME, __FILE__, __LINE__, NULL, false, ::cv::instr::TYPE_MARKER, IMPL);}
///// General instrumentation
// General OpenCV region instrumentation macro
@@ -769,10 +720,6 @@ CV_EXPORTS InstrNode* getCurrentNode();
///// IPP instrumentation
// Wrapper region instrumentation macro
#define CV_INSTRUMENT_REGION_IPP(); CV_INSTRUMENT_REGION_META(__FUNCTION__, false, ::cv::instr::TYPE_WRAPPER, ::cv::instr::IMPL_IPP)
// Function instrumentation macro
#define CV_INSTRUMENT_FUN_IPP(FUN, ...) CV_INSTRUMENT_FUN_RT_META(::cv::instr::TYPE_FUN, ::cv::instr::IMPL_IPP, instrStatus < 0, FUN, __VA_ARGS__)
// Diagnostic markers
#define CV_INSTRUMENT_MARK_IPP(NAME) CV_INSTRUMENT_MARK_META(::cv::instr::IMPL_IPP, NAME)
///// OpenCL instrumentation
// Wrapper region instrumentation macro
@@ -0,0 +1,88 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2026, Intel Corporation, all rights reserved.
#ifndef OPENCV_CORE_UTILS_INSTRUMENTATION_PRIVATE_HPP
#define OPENCV_CORE_UTILS_INSTRUMENTATION_PRIVATE_HPP
#include "opencv2/core/utils/instrumentation.hpp"
// Region-based function-instrumentation primitives.
//
// Only meaningful when the build was configured with ENABLE_INSTRUMENTATION;
// otherwise this header contributes nothing and each includer provides its own
// no-op fallbacks. The IntrumentationRegion / getCurrentNode() definitions are
// compiled into and exported (CV_EXPORTS) from the core library, so the HAL only
// needs these declarations and resolves the symbols at link time.
#ifdef ENABLE_INSTRUMENTATION
namespace cv { namespace instr {
// Scoped region: records one instrumentation node on construction and closes it
// on destruction. Defined in modules/core/src/system.cpp.
class CV_EXPORTS IntrumentationRegion
{
public:
IntrumentationRegion(const char* funName, const char* fileName, int lineNum, void *retAddress,
bool alwaysExpand, TYPE instrType = TYPE_GENERAL, IMPL implType = IMPL_PLAIN);
~IntrumentationRegion();
private:
bool m_disabled; // region status
uint64 m_regionTicks;
};
CV_EXPORTS InstrNode* getCurrentNode();
}} // namespace cv::instr
// Instrumentation information marker
#define CV_INSTRUMENT_MARK_META(IMPL, NAME, ...) {::cv::instr::IntrumentationRegion __instr_mark__(NAME, __FILE__, __LINE__, NULL, false, ::cv::instr::TYPE_MARKER, IMPL);}
// Instrument functions with non-void return type
#define CV_INSTRUMENT_FUN_RT_META(TYPE, IMPL, ERROR_COND, FUN, ...) ([&]() \
{ \
if(::cv::instr::useInstrumentation()){ \
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL); \
try{ \
auto instrStatus = ((FUN)(__VA_ARGS__)); \
if(ERROR_COND){ \
::cv::instr::getCurrentNode()->m_payload.m_funError = true; \
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit"); \
} \
return instrStatus; \
}catch(...){ \
::cv::instr::getCurrentNode()->m_payload.m_funError = true; \
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit"); \
throw; \
} \
}else{ \
return ((FUN)(__VA_ARGS__)); \
} \
}())
// Instrument functions with void return type
#define CV_INSTRUMENT_FUN_RV_META(TYPE, IMPL, FUN, ...) ([&]() \
{ \
if(::cv::instr::useInstrumentation()){ \
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL); \
try{ \
(FUN)(__VA_ARGS__); \
}catch(...){ \
::cv::instr::getCurrentNode()->m_payload.m_funError = true; \
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit"); \
throw; \
} \
}else{ \
(FUN)(__VA_ARGS__); \
} \
}())
// IPP function instrumentation macros
#define CV_INSTRUMENT_FUN_IPP(FUN, ...) CV_INSTRUMENT_FUN_RT_META(::cv::instr::TYPE_FUN, ::cv::instr::IMPL_IPP, instrStatus < 0, FUN, __VA_ARGS__)
#define CV_INSTRUMENT_MARK_IPP(NAME) CV_INSTRUMENT_MARK_META(::cv::instr::IMPL_IPP, NAME)
#endif // ENABLE_INSTRUMENTATION
#endif // OPENCV_CORE_UTILS_INSTRUMENTATION_PRIVATE_HPP
+6 -6
View File
@@ -169,13 +169,13 @@ void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step,
ushort* bgr, int bgr_step, Size size )
{
int i;
for( ; size.height--; gray += gray_step/sizeof(gray[0]) )
for( ; size.height--; gray += gray_step/(int)sizeof(gray[0]) )
{
for( i = 0; i < size.width; i++, bgr += 3 )
{
bgr[0] = bgr[1] = bgr[2] = gray[i];
}
bgr += bgr_step/sizeof(bgr[0]) - size.width*3;
bgr += bgr_step/(int)sizeof(bgr[0]) - size.width*3;
}
}
@@ -214,8 +214,8 @@ void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step,
bgr[0] = t0; bgr[1] = t1;
t0 = bgra[swap_rb^2]; bgr[2] = t0;
}
bgr += bgr_step/sizeof(bgr[0]) - size.width*3;
bgra += bgra_step/sizeof(bgra[0]) - size.width*4;
bgr += bgr_step/(int)sizeof(bgr[0]) - size.width*3;
bgra += bgra_step/(int)sizeof(bgra[0]) - size.width*4;
}
}
@@ -252,8 +252,8 @@ void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step,
rgba[0] = t2; rgba[1] = t1;
rgba[2] = t0; rgba[3] = t3;
}
bgra += bgra_step/sizeof(bgra[0]) - size.width*4;
rgba += rgba_step/sizeof(rgba[0]) - size.width*4;
bgra += bgra_step/(int)sizeof(bgra[0]) - size.width*4;
rgba += rgba_step/(int)sizeof(rgba[0]) - size.width*4;
}
}
+22
View File
@@ -689,6 +689,28 @@ TEST(Imgcodecs_Tiff, readWrite_unsigned)
EXPECT_EQ(0, remove(filenameOutput.c_str()));
}
// See https://github.com/opencv/opencv/issues/29615
// Decoding a 16-bit 4-channel TIFF used to form an out of range pointer in
// icvCvt_BGRA2RGBA_16u_C4R because the byte step was divided by an unsigned
// sizeof and then had size.width*4 subtracted, which wraps around for a zero
// step. This just checks that a 16UC4 TIFF round-trips correctly; the value is
// mainly that the sanitizer builds no longer report the pointer overflow.
TEST(Imgcodecs_Tiff, regression_29615_16UC4)
{
Mat img(4, 3, CV_16UC4);
randu(img, Scalar::all(0), Scalar::all(65535));
vector<uchar> buf;
ASSERT_NO_THROW(ASSERT_TRUE(imencode(".tiff", img, buf)));
Mat decoded;
ASSERT_NO_THROW(decoded = imdecode(buf, IMREAD_UNCHANGED));
ASSERT_FALSE(decoded.empty());
ASSERT_EQ(CV_16UC4, decoded.type());
ASSERT_EQ(img.size(), decoded.size());
EXPECT_EQ(0, cvtest::norm(img, decoded, NORM_INF));
}
TEST(Imgcodecs_Tiff, readWrite_32FC1)
{
const string root = cvtest::TS::ptr()->get_data_path();
+5 -1
View File
@@ -1839,12 +1839,14 @@ int DTreesImpl::readSplit( const FileNode& fn )
Split split;
int vi = (int)fn["var"];
CV_Assert( 0 <= vi && vi <= (int)varType.size() );
CV_Assert( 0 <= vi && vi < (int)varMapping.size() );
vi = varMapping[vi]; // convert to varIdx if needed
CV_Assert( 0 <= vi && vi < (int)varType.size() );
split.varIdx = vi;
if( varType[vi] == VAR_CATEGORICAL ) // split on categorical var
{
CV_Assert( vi < (int)catOfs.size() );
int i, val, ssize = getSubsetSize(vi);
split.subsetOfs = (int)subsets.size();
for( i = 0; i < ssize; i++ )
@@ -1860,6 +1862,7 @@ int DTreesImpl::readSplit( const FileNode& fn )
if( fns.isInt() )
{
val = (int)fns;
CV_Assert( 0 <= val && (val >> 5) < ssize );
subset[val >> 5] |= 1 << (val & 31);
}
else
@@ -1869,6 +1872,7 @@ int DTreesImpl::readSplit( const FileNode& fn )
for( i = 0; i < n; i++, ++it )
{
val = (int)*it;
CV_Assert( 0 <= val && (val >> 5) < ssize );
subset[val >> 5] |= 1 << (val & 31);
}
}
+55
View File
@@ -96,6 +96,61 @@ ML_Legacy_Param param_list[] = {
INSTANTIATE_TEST_CASE_P(/**/, ML_Legacy_Params, testing::ValuesIn(param_list));
TEST(ML_DTrees, load_bad_categorical_split)
{
// Train a tree with a categorical input so the model carries a
// categorical split serialized as an "in"/"not_in" value list.
const int n = 40;
Mat samples(n, 1, CV_32F);
Mat responses(n, 1, CV_32S);
for (int i = 0; i < n; i++)
{
int cat = i % 4;
samples.at<float>(i, 0) = (float)cat;
responses.at<int>(i, 0) = (cat == 1 || cat == 2) ? 1 : 0;
}
Mat varType(2, 1, CV_8U);
varType.at<uchar>(0) = ml::VAR_CATEGORICAL;
varType.at<uchar>(1) = ml::VAR_CATEGORICAL;
Ptr<ml::TrainData> td = ml::TrainData::create(samples, ml::ROW_SAMPLE, responses,
noArray(), noArray(), noArray(), varType);
Ptr<ml::DTrees> dt = ml::DTrees::create();
dt->setMaxDepth(4);
dt->setCVFolds(0);
dt->setMaxCategories(4);
dt->setMinSampleCount(1);
dt->train(td);
const string filename = cv::tempfile(".yml");
dt->save(filename);
string model;
{
std::ifstream in(filename.c_str());
std::stringstream ss;
ss << in.rdbuf();
model = ss.str();
}
// Category values in the split list index a per-split subset bitmask.
// Injecting a value larger than the number of categories used to write
// past that bitmask; loading such a model must be rejected, not crash.
size_t pos = model.find("in:");
ASSERT_NE(pos, string::npos);
size_t br = model.find('[', pos);
ASSERT_NE(br, string::npos);
model.insert(br + 1, "1000000,");
{
std::ofstream out(filename.c_str());
out << model;
}
Ptr<ml::DTrees> bad;
EXPECT_THROW(bad = ml::DTrees::load(filename), Exception);
remove(filename.c_str());
}
/*TEST(ML_SVM, throw_exception_when_save_untrained_model)
{
Ptr<cv::ml::SVM> svm;
+1 -1
View File
@@ -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);
@@ -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