From ce31c9c448e093600b6daccbc82026c972a818b7 Mon Sep 17 00:00:00 2001 From: Jiri Kucera Date: Tue, 14 Apr 2020 14:23:43 +0200 Subject: [PATCH] core(matrix): Negative values checks Add checks that prevents indexing an array by negative values. --- modules/core/src/matrix_wrap.cpp | 32 +++----- modules/core/test/test_mat.cpp | 153 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+), 20 deletions(-) diff --git a/modules/core/src/matrix_wrap.cpp b/modules/core/src/matrix_wrap.cpp index 4c5efd6..0a8d6c1 100644 --- a/modules/core/src/matrix_wrap.cpp +++ b/modules/core/src/matrix_wrap.cpp @@ -947,7 +947,7 @@ bool _InputArray::isContinuous(int i) const if( k == STD_ARRAY_MAT ) { const Mat* vv = (const Mat*)obj; - CV_Assert(i > 0 && i < sz.height); + CV_Assert(i >= 0 && i < sz.height); return vv[i].isContinuous(); } @@ -981,21 +981,21 @@ bool _InputArray::isSubmatrix(int i) const if( k == STD_VECTOR_MAT ) { const std::vector& vv = *(const std::vector*)obj; - CV_Assert((size_t)i < vv.size()); + CV_Assert(i >= 0 && (size_t)i < vv.size()); return vv[i].isSubmatrix(); } if( k == STD_ARRAY_MAT ) { const Mat* vv = (const Mat*)obj; - CV_Assert(i < sz.height); + CV_Assert(i >= 0 && i < sz.height); return vv[i].isSubmatrix(); } if( k == STD_VECTOR_UMAT ) { const std::vector& vv = *(const std::vector*)obj; - CV_Assert((size_t)i < vv.size()); + CV_Assert(i >= 0 && (size_t)i < vv.size()); return vv[i].isSubmatrix(); } @@ -1026,9 +1026,7 @@ size_t _InputArray::offset(int i) const if( k == STD_VECTOR_MAT ) { const std::vector& vv = *(const std::vector*)obj; - if( i < 0 ) - return 1; - CV_Assert( i < (int)vv.size() ); + CV_Assert( i >= 0 && i < (int)vv.size() ); return (size_t)(vv[i].ptr() - vv[i].datastart); } @@ -1036,16 +1034,14 @@ size_t _InputArray::offset(int i) const if( k == STD_ARRAY_MAT ) { const Mat* vv = (const Mat*)obj; - if( i < 0 ) - return 1; - CV_Assert( i < sz.height ); + CV_Assert( i >= 0 && i < sz.height ); return (size_t)(vv[i].ptr() - vv[i].datastart); } if( k == STD_VECTOR_UMAT ) { const std::vector& vv = *(const std::vector*)obj; - CV_Assert((size_t)i < vv.size()); + CV_Assert(i >= 0 && (size_t)i < vv.size()); return vv[i].offset; } @@ -1059,7 +1055,7 @@ size_t _InputArray::offset(int i) const if (k == STD_VECTOR_CUDA_GPU_MAT) { const std::vector& vv = *(const std::vector*)obj; - CV_Assert((size_t)i < vv.size()); + CV_Assert(i >= 0 && (size_t)i < vv.size()); return (size_t)(vv[i].data - vv[i].datastart); } @@ -1089,25 +1085,21 @@ size_t _InputArray::step(int i) const if( k == STD_VECTOR_MAT ) { const std::vector& vv = *(const std::vector*)obj; - if( i < 0 ) - return 1; - CV_Assert( i < (int)vv.size() ); + CV_Assert( i >= 0 && i < (int)vv.size() ); return vv[i].step; } if( k == STD_ARRAY_MAT ) { const Mat* vv = (const Mat*)obj; - if( i < 0 ) - return 1; - CV_Assert( i < sz.height ); + CV_Assert( i >= 0 && i < sz.height ); return vv[i].step; } if( k == STD_VECTOR_UMAT ) { const std::vector& vv = *(const std::vector*)obj; - CV_Assert((size_t)i < vv.size()); + CV_Assert(i >= 0 && (size_t)i < vv.size()); return vv[i].step; } @@ -1119,7 +1111,7 @@ size_t _InputArray::step(int i) const if (k == STD_VECTOR_CUDA_GPU_MAT) { const std::vector& vv = *(const std::vector*)obj; - CV_Assert((size_t)i < vv.size()); + CV_Assert(i >= 0 && (size_t)i < vv.size()); return vv[i].step; } diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 58eafd0..90ebd04 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -9,6 +9,8 @@ #include "opencv2/core/eigen.hpp" #endif +#include "opencv2/core/cuda.hpp" + namespace opencv_test { namespace { class Core_ReduceTest : public cvtest::BaseTest @@ -1984,6 +1986,157 @@ TEST(Core_InputArray, fetch_MatExpr) } +#ifdef CV_CXX11 +class TestInputArrayRangeChecking { + static const char *kind2str(cv::_InputArray ia) + { + switch (ia.kind()) + { + #define C(x) case cv::_InputArray::x: return #x + C(MAT); + C(UMAT); + C(EXPR); + C(MATX); + C(STD_VECTOR); + C(STD_ARRAY); + C(NONE); + C(STD_VECTOR_VECTOR); + C(STD_BOOL_VECTOR); + C(STD_VECTOR_MAT); + C(STD_ARRAY_MAT); + C(STD_VECTOR_UMAT); + C(CUDA_GPU_MAT); + C(STD_VECTOR_CUDA_GPU_MAT); + #undef C + default: + return ""; + } + } + + static void banner(cv::_InputArray ia, const char *label, const char *name) + { + std::cout << std::endl + << label << " = " << name << ", Kind: " << kind2str(ia) + << std::endl; + } + + template + static void testA(I ia, F f, const char *mfname) + { + banner(ia, "f", mfname); + EXPECT_THROW(f(ia, -1), cv::Exception) + << "f(ia, " << -1 << ") should throw cv::Exception"; + for (int i = 0; i < int(ia.size()); i++) + { + EXPECT_NO_THROW(f(ia, i)) + << "f(ia, " << i << ") should not throw an exception"; + } + EXPECT_THROW(f(ia, int(ia.size())), cv::Exception) + << "f(ia, " << ia.size() << ") should throw cv::Exception"; + } + + template + static void testB(I ia, F f, const char *mfname) + { + banner(ia, "f", mfname); + EXPECT_THROW(f(ia, -1), cv::Exception) + << "f(ia, " << -1 << ") should throw cv::Exception"; + for (int i = 0; i < int(ia.size()); i++) + { + EXPECT_NO_THROW(f(ia, i)) + << "f(ia, " << i << ") should not throw an exception"; + } + EXPECT_THROW(f(ia, int(ia.size())), cv::Exception) + << "f(ia, " << ia.size() << ") should throw cv::Exception"; + } + + static void test_isContinuous() + { + auto f = [](cv::_InputArray ia, int i) { (void)ia.isContinuous(i); }; + + cv::Mat M; + cv::UMat uM; + + std::vector vec = {M, M}; + std::array arr = {M, M}; + std::vector uvec = {uM, uM}; + + testA(vec, f, "isContinuous"); + testA(arr, f, "isContinuous"); + testA(uvec, f, "isContinuous"); + } + + static void test_isSubmatrix() + { + auto f = [](cv::_InputArray ia, int i) { (void)ia.isSubmatrix(i); }; + + cv::Mat M; + cv::UMat uM; + + std::vector vec = {M, M}; + std::array arr = {M, M}; + std::vector uvec = {uM, uM}; + + testA(vec, f, "isSubmatrix"); + testA(arr, f, "isSubmatrix"); + testA(uvec, f, "isSubmatrix"); + } + + static void test_offset() + { + auto f = [](cv::_InputArray ia, int i) { return ia.offset(i); }; + + cv::Mat M; + cv::UMat uM; + cv::cuda::GpuMat gM; + + std::vector vec = {M, M}; + std::array arr = {M, M}; + std::vector uvec = {uM, uM}; + std::vector gvec = {gM, gM}; + + testB(vec, f, "offset"); + testB(arr, f, "offset"); + testB(uvec, f, "offset"); + testB(gvec, f, "offset"); + } + + static void test_step() + { + auto f = [](cv::_InputArray ia, int i) { return ia.step(i); }; + + cv::Mat M; + cv::UMat uM; + cv::cuda::GpuMat gM; + + std::vector vec = {M, M}; + std::array arr = {M, M}; + std::vector uvec = {uM, uM}; + std::vector gvec = {gM, gM}; + + testB(vec, f, "step"); + testB(arr, f, "step"); + testB(uvec, f, "step"); + testB(gvec, f, "step"); + } + +public: + static void run() + { + test_isContinuous(); + test_isSubmatrix(); + test_offset(); + test_step(); + } +}; + +TEST(Core_InputArray, range_checking) +{ + TestInputArrayRangeChecking::run(); +} +#endif + + TEST(Core_Vectors, issue_13078) { float floats_[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; -- 2.7.4