From 999f41fb4f4aa94a0cb47256919ae8b5c29ca5f3 Mon Sep 17 00:00:00 2001
From: Alexander Alekhin <alexander.a.alekhin@gmail.com>
Date: Tue, 15 Aug 2017 22:04:55 +0000
Subject: [PATCH] imgcodecs: refactoring, improve code quality

---
 modules/imgcodecs/src/bitstrm.cpp     |   2 +
 modules/imgcodecs/src/bitstrm.hpp     |  19 +++-
 modules/imgcodecs/src/grfmt_bmp.cpp   |  13 ++-
 modules/imgcodecs/src/grfmt_pxm.cpp   | 121 ++++++++++++--------
 modules/imgcodecs/src/loadsave.cpp    | 157 +++++++++++++++++++++-----
 modules/imgcodecs/test/test_grfmt.cpp |   2 +-
 modules/ts/src/cuda_test.cpp          |  56 +++++----
 7 files changed, 261 insertions(+), 109 deletions(-)

diff --git a/modules/imgcodecs/src/bitstrm.cpp b/modules/imgcodecs/src/bitstrm.cpp
index c47744b..bd7551d 100644
--- a/modules/imgcodecs/src/bitstrm.cpp
+++ b/modules/imgcodecs/src/bitstrm.cpp
@@ -208,6 +208,8 @@ int  RLByteStream::getByte()
         current = m_current;
     }
 
+    CV_Assert(current < m_end);
+
     val = *((uchar*)current);
     m_current = current + 1;
     return val;
diff --git a/modules/imgcodecs/src/bitstrm.hpp b/modules/imgcodecs/src/bitstrm.hpp
index 465c0a8..2694797 100644
--- a/modules/imgcodecs/src/bitstrm.hpp
+++ b/modules/imgcodecs/src/bitstrm.hpp
@@ -48,13 +48,20 @@
 namespace cv
 {
 
-enum
-{
-    RBS_THROW_EOS=-123,  // <end of stream> exception code
-    RBS_THROW_FORB=-124,  // <forrbidden huffman code> exception code
-    RBS_HUFF_FORB=2047,  // forrbidden huffman code "value"
-    RBS_BAD_HEADER=-125 // invalid header
+#define DECLARE_RBS_EXCEPTION(name) \
+class RBS_ ## name ## _Exception : public cv::Exception \
+{ \
+public: \
+    RBS_ ## name ## _Exception(int code_, const String& err_, const String& func_, const String& file_, int line_) : \
+        cv::Exception(code_, err_, func_, file_, line_) \
+    {} \
 };
+DECLARE_RBS_EXCEPTION(THROW_EOS)
+#define RBS_THROW_EOS RBS_THROW_EOS_Exception(cv::Error::StsError, "Unexpected end of input stream", CV_Func, __FILE__, __LINE__)
+DECLARE_RBS_EXCEPTION(THROW_FORB)
+#define RBS_THROW_FORB RBS_THROW_FORB_Exception(cv::Error::StsError, "Forrbidden huffman code", CV_Func, __FILE__, __LINE__)
+DECLARE_RBS_EXCEPTION(BAD_HEADER)
+#define RBS_BAD_HEADER RBS_BAD_HEADER_Exception(cv::Error::StsError, "Invalid header", CV_Func, __FILE__, __LINE__)
 
 typedef unsigned long ulong;
 
diff --git a/modules/imgcodecs/src/grfmt_bmp.cpp b/modules/imgcodecs/src/grfmt_bmp.cpp
index 4063d5b..d68224f 100644
--- a/modules/imgcodecs/src/grfmt_bmp.cpp
+++ b/modules/imgcodecs/src/grfmt_bmp.cpp
@@ -115,8 +115,9 @@ bool  BmpDecoder::readHeader()
 
                 if( m_bpp <= 8 )
                 {
-                    memset( m_palette, 0, sizeof(m_palette));
-                    m_strm.getBytes( m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
+                    CV_Assert(clrused < 256);
+                    memset(m_palette, 0, sizeof(m_palette));
+                    m_strm.getBytes(m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
                     iscolor = IsColorPalette( m_palette, m_bpp );
                 }
                 else if( m_bpp == 16 && m_rle_code == BMP_BITFIELDS )
@@ -287,7 +288,9 @@ bool  BmpDecoder::readData( Mat& img )
                     else if( code > 2 ) // absolute mode
                     {
                         if( data + code*nch > line_end ) goto decode_rle4_bad;
-                        m_strm.getBytes( src, (((code + 1)>>1) + 1) & -2 );
+                        int sz = (((code + 1)>>1) + 1) & (~1);
+                        CV_Assert((size_t)sz < _src.size());
+                        m_strm.getBytes(src, sz);
                         if( color )
                             data = FillColorRow4( data, src, code, m_palette );
                         else
@@ -376,7 +379,9 @@ decode_rle4_bad: ;
 
                         if( data + code3 > line_end )
                             goto decode_rle8_bad;
-                        m_strm.getBytes( src, (code + 1) & -2 );
+                        int sz = (code + 1) & (~1);
+                        CV_Assert((size_t)sz < _src.size());
+                        m_strm.getBytes(src, sz);
                         if( color )
                             data = FillColorRow8( data, src, code, m_palette );
                         else
diff --git a/modules/imgcodecs/src/grfmt_pxm.cpp b/modules/imgcodecs/src/grfmt_pxm.cpp
index 8afd7b1..7406d4f 100644
--- a/modules/imgcodecs/src/grfmt_pxm.cpp
+++ b/modules/imgcodecs/src/grfmt_pxm.cpp
@@ -43,50 +43,58 @@
 #include "precomp.hpp"
 #include "utils.hpp"
 #include "grfmt_pxm.hpp"
+#include <iostream>
 
 namespace cv
 {
 
 ///////////////////////// P?M reader //////////////////////////////
 
-static int ReadNumber( RLByteStream& strm, int maxdigits )
+static int ReadNumber(RLByteStream& strm, int maxdigits = 0)
 {
     int code;
-    int val = 0;
+    int64 val = 0;
     int digits = 0;
 
     code = strm.getByte();
 
-    if( !isdigit(code))
+    while (!isdigit(code))
     {
-        do
+        if (code == '#' )
         {
-            if( code == '#' )
+            do
             {
-                do
-                {
-                    code = strm.getByte();
-                }
-                while( code != '\n' && code != '\r' );
+                code = strm.getByte();
             }
-
+            while (code != '\n' && code != '\r');
             code = strm.getByte();
-
-            while( isspace(code))
+        }
+        else if (isspace(code))
+        {
+            while (isspace(code))
                 code = strm.getByte();
         }
-        while( !isdigit( code ));
+        else
+        {
+#if 1
+            CV_ErrorNoReturn_(Error::StsError, ("PXM: Unexpected code in ReadNumber(): 0x%x (%d)", code, code));
+#else
+            code = strm.getByte();
+#endif
+        }
     }
 
     do
     {
-        val = val*10 + code - '0';
-        if( ++digits >= maxdigits ) break;
+        val = val*10 + (code - '0');
+        CV_Assert(val <= INT_MAX && "PXM: ReadNumber(): result is too large");
+        digits++;
+        if (maxdigits != 0 && digits >= maxdigits) break;
         code = strm.getByte();
     }
-    while( isdigit(code));
+    while (isdigit(code));
 
-    return val;
+    return (int)val;
 }
 
 
@@ -119,13 +127,13 @@ ImageDecoder PxMDecoder::newDecoder() const
     return makePtr<PxMDecoder>();
 }
 
-void  PxMDecoder::close()
+void PxMDecoder::close()
 {
     m_strm.close();
 }
 
 
-bool  PxMDecoder::readHeader()
+bool PxMDecoder::readHeader()
 {
     bool result = false;
 
@@ -155,10 +163,10 @@ bool  PxMDecoder::readHeader()
         m_binary = code >= '4';
         m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1;
 
-        m_width = ReadNumber( m_strm, INT_MAX );
-        m_height = ReadNumber( m_strm, INT_MAX );
+        m_width = ReadNumber(m_strm);
+        m_height = ReadNumber(m_strm);
 
-        m_maxval = m_bpp == 1 ? 1 : ReadNumber( m_strm, INT_MAX );
+        m_maxval = m_bpp == 1 ? 1 : ReadNumber(m_strm);
         if( m_maxval > 65535 )
             throw RBS_BAD_HEADER;
 
@@ -172,8 +180,14 @@ bool  PxMDecoder::readHeader()
             result = true;
         }
     }
-    catch(...)
+    catch (const cv::Exception&)
+    {
+        throw;
+    }
+    catch (...)
     {
+        std::cerr << "PXM::readHeader(): unknown C++ exception" << std::endl << std::flush;
+        throw;
     }
 
     if( !result )
@@ -186,33 +200,28 @@ bool  PxMDecoder::readHeader()
 }
 
 
-bool  PxMDecoder::readData( Mat& img )
+bool PxMDecoder::readData( Mat& img )
 {
     int color = img.channels() > 1;
     uchar* data = img.ptr();
     PaletteEntry palette[256];
     bool   result = false;
-    int  bit_depth = CV_ELEM_SIZE1(m_type)*8;
-    int  src_pitch = (m_width*m_bpp*bit_depth/8 + 7)/8;
+    const int bit_depth = CV_ELEM_SIZE1(m_type)*8;
+    const int src_pitch = (m_width*m_bpp*(bit_depth/8) + 7) / 8;
     int  nch = CV_MAT_CN(m_type);
     int  width3 = m_width*nch;
-    int  i, x, y;
 
     if( m_offset < 0 || !m_strm.isOpened())
         return false;
 
-    AutoBuffer<uchar> _src(src_pitch + 32);
-    uchar* src = _src;
-    AutoBuffer<uchar> _gray_palette;
-    uchar* gray_palette = _gray_palette;
+    uchar gray_palette[256] = {0};
 
     // create LUT for converting colors
     if( bit_depth == 8 )
     {
-        _gray_palette.allocate(m_maxval + 1);
-        gray_palette = _gray_palette;
+        CV_Assert(m_maxval < 256);
 
-        for( i = 0; i <= m_maxval; i++ )
+        for (int i = 0; i <= m_maxval; i++)
             gray_palette[i] = (uchar)((i*255/m_maxval)^(m_bpp == 1 ? 255 : 0));
 
         FillGrayPalette( palette, m_bpp==1 ? 1 : 8 , m_bpp == 1 );
@@ -226,12 +235,16 @@ bool  PxMDecoder::readData( Mat& img )
         {
         ////////////////////////// 1 BPP /////////////////////////
         case 1:
+            CV_Assert(CV_MAT_DEPTH(m_type) == CV_8U);
             if( !m_binary )
             {
-                for( y = 0; y < m_height; y++, data += img.step )
+                AutoBuffer<uchar> _src(m_width);
+                uchar* src = _src;
+
+                for (int y = 0; y < m_height; y++, data += img.step)
                 {
-                    for( x = 0; x < m_width; x++ )
-                        src[x] = ReadNumber( m_strm, 1 ) != 0;
+                    for (int x = 0; x < m_width; x++)
+                        src[x] = ReadNumber(m_strm, 1) != 0;
 
                     if( color )
                         FillColorRow8( data, src, m_width, palette );
@@ -241,7 +254,10 @@ bool  PxMDecoder::readData( Mat& img )
             }
             else
             {
-                for( y = 0; y < m_height; y++, data += img.step )
+                AutoBuffer<uchar> _src(src_pitch);
+                uchar* src = _src;
+
+                for (int y = 0; y < m_height; y++, data += img.step)
                 {
                     m_strm.getBytes( src, src_pitch );
 
@@ -257,13 +273,16 @@ bool  PxMDecoder::readData( Mat& img )
         ////////////////////////// 8 BPP /////////////////////////
         case 8:
         case 24:
-            for( y = 0; y < m_height; y++, data += img.step )
+        {
+            AutoBuffer<uchar> _src(std::max<size_t>(width3*2, src_pitch));
+            uchar* src = _src;
+            for (int y = 0; y < m_height; y++, data += img.step)
             {
                 if( !m_binary )
                 {
-                    for( x = 0; x < width3; x++ )
+                    for (int x = 0; x < width3; x++)
                     {
-                        int code = ReadNumber( m_strm, INT_MAX );
+                        int code = ReadNumber(m_strm);
                         if( (unsigned)code > (unsigned)m_maxval ) code = m_maxval;
                         if( bit_depth == 8 )
                             src[x] = gray_palette[code];
@@ -276,7 +295,7 @@ bool  PxMDecoder::readData( Mat& img )
                     m_strm.getBytes( src, src_pitch );
                     if( bit_depth == 16 && !isBigEndian() )
                     {
-                        for( x = 0; x < width3; x++ )
+                        for (int x = 0; x < width3; x++)
                         {
                             uchar v = src[x * 2];
                             src[x * 2] = src[x * 2 + 1];
@@ -287,7 +306,7 @@ bool  PxMDecoder::readData( Mat& img )
 
                 if( img.depth() == CV_8U && bit_depth == 16 )
                 {
-                    for( x = 0; x < width3; x++ )
+                    for (int x = 0; x < width3; x++)
                     {
                         int v = ((ushort *)src)[x];
                         src[x] = (uchar)(v >> 8);
@@ -328,12 +347,19 @@ bool  PxMDecoder::readData( Mat& img )
             }
             result = true;
             break;
+        }
         default:
-            assert(0);
+            CV_ErrorNoReturn(Error::StsError, "m_bpp is not supported");
         }
     }
-    catch(...)
+    catch (const cv::Exception&)
+    {
+        throw;
+    }
+    catch (...)
     {
+        std::cerr << "PXM::readData(): unknown exception" << std::endl << std::flush;
+        throw;
     }
 
     return result;
@@ -409,8 +435,9 @@ bool  PxMEncoder::write( const Mat& img, const std::vector<int>& params )
     char* buffer = _buffer;
 
     // write header;
-    sprintf( buffer, "P%c\n%d %d\n%d\n",
+    sprintf( buffer, "P%c\n# Generated by OpenCV %s\n%d %d\n%d\n",
              '2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0),
+             CV_VERSION,
              width, height, (1 << depth) - 1 );
 
     strm.putBytes( buffer, (int)strlen(buffer) );
diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp
index 493ccab..a656834 100644
--- a/modules/imgcodecs/src/loadsave.cpp
+++ b/modules/imgcodecs/src/loadsave.cpp
@@ -57,6 +57,23 @@
 namespace cv
 {
 
+// TODO Add runtime configuration
+#define CV_IO_MAX_IMAGE_PARAMS (50)
+#define CV_IO_MAX_IMAGE_WIDTH (1<<20)
+#define CV_IO_MAX_IMAGE_HEIGHT (1<<20)
+#define CV_IO_MAX_IMAGE_PIXELS (1<<30) // 1 Gigapixel
+static Size validateInputImageSize(const Size& size)
+{
+    CV_Assert(size.width > 0);
+    CV_Assert(size.width <= CV_IO_MAX_IMAGE_WIDTH);
+    CV_Assert(size.height > 0);
+    CV_Assert(size.height <= CV_IO_MAX_IMAGE_HEIGHT);
+    uint64 pixels = (uint64)size.width * (uint64)size.height;
+    CV_Assert(pixels <= CV_IO_MAX_IMAGE_PIXELS);
+    return size;
+}
+
+
 /**
  * @struct ImageCodecInitializer
  *
@@ -339,14 +356,27 @@ imread_( const String& filename, int flags, int hdrtype, Mat* mat=0 )
     /// set the filename in the driver
     decoder->setSource( filename );
 
-   // read the header to make sure it succeeds
-   if( !decoder->readHeader() )
+    // read the header to make sure it succeeds
+    try
+    {
+        // read the header to make sure it succeeds
+        if( !decoder->readHeader() )
+            return 0;
+    }
+    catch (const cv::Exception& e)
+    {
+        std::cerr << "imread_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
+        return 0;
+    }
+    catch (...)
+    {
+        std::cerr << "imread_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
         return 0;
+    }
+
 
     // established the required input image size
-    CvSize size;
-    size.width = decoder->width();
-    size.height = decoder->height();
+    Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
 
     // grab the decoded type
     int type = decoder->type();
@@ -382,7 +412,21 @@ imread_( const String& filename, int flags, int hdrtype, Mat* mat=0 )
     }
 
     // read the image data
-    if( !decoder->readData( *data ))
+    bool success = false;
+    try
+    {
+        if (decoder->readData(*data))
+            success = true;
+    }
+    catch (const cv::Exception& e)
+    {
+        std::cerr << "imread_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
+    }
+    catch (...)
+    {
+        std::cerr << "imread_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
+    }
+    if (!success)
     {
         cvReleaseImage( &image );
         cvReleaseMat( &matrix );
@@ -435,8 +479,22 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
     decoder->setSource(filename);
 
     // read the header to make sure it succeeds
-    if (!decoder->readHeader())
+    try
+    {
+        // read the header to make sure it succeeds
+        if( !decoder->readHeader() )
+            return 0;
+    }
+    catch (const cv::Exception& e)
+    {
+        std::cerr << "imreadmulti_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
+        return 0;
+    }
+    catch (...)
+    {
+        std::cerr << "imreadmulti_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
         return 0;
+    }
 
     for (;;)
     {
@@ -454,17 +512,33 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
                 type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
         }
 
+        // established the required input image size
+        Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
+
         // read the image data
-        Mat mat(decoder->height(), decoder->width(), type);
-        if (!decoder->readData(mat))
+        Mat mat(size.height, size.width, type);
+        bool success = false;
+        try
         {
-            // optionally rotate the data if EXIF' orientation flag says so
-            if( (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
-            {
-                ApplyExifOrientation(filename, mat);
-            }
 
+            if (decoder->readData(mat))
+                success = true;
+        }
+        catch (const cv::Exception& e)
+        {
+            std::cerr << "imreadmulti_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
+        }
+        catch (...)
+        {
+            std::cerr << "imreadmulti_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
+        }
+        if (!success)
             break;
+
+        // optionally rotate the data if EXIF' orientation flag says so
+        if( (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
+        {
+            ApplyExifOrientation(filename, mat);
         }
 
         mats.push_back(mat);
@@ -543,6 +617,7 @@ static bool imwrite_( const String& filename, const Mat& image,
     }
 
     encoder->setDestination( filename );
+    CV_Assert(params.size() <= CV_IO_MAX_IMAGE_PARAMS*2);
     bool code = encoder->write( *pimage, params );
 
     //    CV_Assert( code );
@@ -581,22 +656,35 @@ imdecode_( const Mat& buf, int flags, int hdrtype, Mat* mat=0 )
         decoder->setSource(filename);
     }
 
-    if( !decoder->readHeader() )
+    bool success = false;
+    try
+    {
+        if (decoder->readHeader())
+            success = true;
+    }
+    catch (const cv::Exception& e)
+    {
+        std::cerr << "imdecode_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
+    }
+    catch (...)
+    {
+        std::cerr << "imdecode_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
+    }
+    if (!success)
     {
         decoder.release();
-        if ( !filename.empty() )
+        if (!filename.empty())
         {
-            if ( remove(filename.c_str()) != 0 )
+            if (0 != remove(filename.c_str()))
             {
-                CV_Error( CV_StsError, "unable to remove temporary file" );
+                std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
             }
         }
         return 0;
     }
 
-    CvSize size;
-    size.width = decoder->width();
-    size.height = decoder->height();
+    // established the required input image size
+    Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
 
     int type = decoder->type();
     if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED )
@@ -630,17 +718,30 @@ imdecode_( const Mat& buf, int flags, int hdrtype, Mat* mat=0 )
         temp = cvarrToMat(image);
     }
 
-    bool code = decoder->readData( *data );
+    success = false;
+    try
+    {
+        if (decoder->readData(*data))
+            success = true;
+    }
+    catch (const cv::Exception& e)
+    {
+        std::cerr << "imdecode_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
+    }
+    catch (...)
+    {
+        std::cerr << "imdecode_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
+    }
     decoder.release();
-    if ( !filename.empty() )
+    if (!filename.empty())
     {
-        if ( remove(filename.c_str()) != 0 )
+        if (0 != remove(filename.c_str()))
         {
-            CV_Error( CV_StsError, "unable to remove temporary file" );
+            std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
         }
     }
 
-    if( !code )
+    if (!success)
     {
         cvReleaseImage( &image );
         cvReleaseMat( &matrix );
@@ -757,7 +858,7 @@ cvSaveImage( const char* filename, const CvArr* arr, const int* _params )
     if( _params )
     {
         for( ; _params[i] > 0; i += 2 )
-            ;
+            CV_Assert(i < CV_IO_MAX_IMAGE_PARAMS*2); // Limit number of params for security reasons
     }
     return cv::imwrite_(filename, cv::cvarrToMat(arr),
         i > 0 ? std::vector<int>(_params, _params+i) : std::vector<int>(),
@@ -788,7 +889,7 @@ cvEncodeImage( const char* ext, const CvArr* arr, const int* _params )
     if( _params )
     {
         for( ; _params[i] > 0; i += 2 )
-            ;
+            CV_Assert(i < CV_IO_MAX_IMAGE_PARAMS*2); // Limit number of params for security reasons
     }
     cv::Mat img = cv::cvarrToMat(arr);
     if( CV_IS_IMAGE(arr) && ((const IplImage*)arr)->origin == IPL_ORIGIN_BL )
diff --git a/modules/imgcodecs/test/test_grfmt.cpp b/modules/imgcodecs/test/test_grfmt.cpp
index faca3d7..5f7f279 100644
--- a/modules/imgcodecs/test/test_grfmt.cpp
+++ b/modules/imgcodecs/test/test_grfmt.cpp
@@ -784,7 +784,7 @@ TEST(Imgcodecs_Tiff, write_read_16bit_big_little_endian)
         EXPECT_EQ(0xDEAD, img.at<ushort>(0,0));
         EXPECT_EQ(0xBEEF, img.at<ushort>(0,1));
 
-        remove(filename.c_str());
+        EXPECT_EQ(0, remove(filename.c_str()));
     }
 }
 
diff --git a/modules/ts/src/cuda_test.cpp b/modules/ts/src/cuda_test.cpp
index a48e0a0..eb4cee1 100644
--- a/modules/ts/src/cuda_test.cpp
+++ b/modules/ts/src/cuda_test.cpp
@@ -322,16 +322,20 @@ namespace cvtest
 
         if (m1.size() != m2.size())
         {
-            return AssertionFailure() << "Matrices \"" << expr1 << "\" and \"" << expr2 << "\" have different sizes : \""
-                                      << expr1 << "\" [" << PrintToString(m1.size()) << "] vs \""
-                                      << expr2 << "\" [" << PrintToString(m2.size()) << "]";
+            std::stringstream msg;
+            msg << "Matrices \"" << expr1 << "\" and \"" << expr2 << "\" have different sizes : \""
+                << expr1 << "\" [" << PrintToString(m1.size()) << "] vs \""
+                << expr2 << "\" [" << PrintToString(m2.size()) << "]";
+            return AssertionFailure() << msg.str();
         }
 
         if (m1.type() != m2.type())
         {
-            return AssertionFailure() << "Matrices \"" << expr1 << "\" and \"" << expr2 << "\" have different types : \""
-                                      << expr1 << "\" [" << PrintToString(MatType(m1.type())) << "] vs \""
-                                      << expr2 << "\" [" << PrintToString(MatType(m2.type())) << "]";
+            std::stringstream msg;
+            msg << "Matrices \"" << expr1 << "\" and \"" << expr2 << "\" have different types : \""
+                << expr1 << "\" [" << PrintToString(MatType(m1.type())) << "] vs \""
+                << expr2 << "\" [" << PrintToString(MatType(m2.type())) << "]";
+             return AssertionFailure() << msg.str();
         }
 
         Mat diff;
@@ -343,12 +347,14 @@ namespace cvtest
 
         if (maxVal > eps)
         {
-            return AssertionFailure() << "The max difference between matrices \"" << expr1 << "\" and \"" << expr2
-                                      << "\" is " << maxVal << " at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ")"
-                                      << ", which exceeds \"" << eps_expr << "\", where \""
-                                      << expr1 << "\" at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ") evaluates to " << printMatVal(m1, maxLoc) << ", \""
-                                      << expr2 << "\" at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ") evaluates to " << printMatVal(m2, maxLoc) << ", \""
-                                      << eps_expr << "\" evaluates to " << eps;
+            std::stringstream msg;
+            msg << "The max difference between matrices \"" << expr1 << "\" and \"" << expr2
+                << "\" is " << maxVal << " at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ")"
+                << ", which exceeds \"" << eps_expr << "\", where \""
+                << expr1 << "\" at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ") evaluates to " << printMatVal(m1, maxLoc) << ", \""
+                << expr2 << "\" at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ") evaluates to " << printMatVal(m2, maxLoc) << ", \""
+                << eps_expr << "\" evaluates to " << eps;
+            return AssertionFailure() << msg.str();
         }
 
         return AssertionSuccess();
@@ -469,9 +475,11 @@ namespace cvtest
     {
         if (gold.size() != actual.size())
         {
-            return testing::AssertionFailure() << "KeyPoints size mistmach\n"
-                                               << "\"" << gold_expr << "\" : " << gold.size() << "\n"
-                                               << "\"" << actual_expr << "\" : " << actual.size();
+            std::stringstream msg;
+            msg << "KeyPoints size mistmach\n"
+                << "\"" << gold_expr << "\" : " << gold.size() << "\n"
+                << "\"" << actual_expr << "\" : " << actual.size();
+            return AssertionFailure() << msg.str();
         }
 
         std::sort(actual.begin(), actual.end(), KeyPointLess());
@@ -484,14 +492,16 @@ namespace cvtest
 
             if (!keyPointsEquals(p1, p2))
             {
-                return testing::AssertionFailure() << "KeyPoints differ at " << i << "\n"
-                                                   << "\"" << gold_expr << "\" vs \"" << actual_expr << "\" : \n"
-                                                   << "pt : " << testing::PrintToString(p1.pt) << " vs " << testing::PrintToString(p2.pt) << "\n"
-                                                   << "size : " << p1.size << " vs " << p2.size << "\n"
-                                                   << "angle : " << p1.angle << " vs " << p2.angle << "\n"
-                                                   << "response : " << p1.response << " vs " << p2.response << "\n"
-                                                   << "octave : " << p1.octave << " vs " << p2.octave << "\n"
-                                                   << "class_id : " << p1.class_id << " vs " << p2.class_id;
+                std::stringstream msg;
+                msg << "KeyPoints differ at " << i << "\n"
+                    << "\"" << gold_expr << "\" vs \"" << actual_expr << "\" : \n"
+                    << "pt : " << testing::PrintToString(p1.pt) << " vs " << testing::PrintToString(p2.pt) << "\n"
+                    << "size : " << p1.size << " vs " << p2.size << "\n"
+                    << "angle : " << p1.angle << " vs " << p2.angle << "\n"
+                    << "response : " << p1.response << " vs " << p2.response << "\n"
+                    << "octave : " << p1.octave << " vs " << p2.octave << "\n"
+                    << "class_id : " << p1.class_id << " vs " << p2.class_id;
+                return AssertionFailure() << msg.str();
             }
         }
 
-- 
2.17.1

