Merge pull request #19045 from alalek:issue_17553
authorAlexander Alekhin <alexander.a.alekhin@gmail.com>
Fri, 11 Dec 2020 19:09:35 +0000 (22:09 +0300)
committerGitHub <noreply@github.com>
Fri, 11 Dec 2020 19:09:35 +0000 (19:09 +0000)
* flann: avoid dangling pointers on lost features data

* flann: fix Index::load()

modules/features2d/test/test_nearestneighbors.cpp
modules/flann/include/opencv2/flann/miniflann.hpp
modules/flann/src/miniflann.cpp

index f63ebb8..0ea86a8 100644 (file)
@@ -123,7 +123,7 @@ void NearestNeighborTest::run( int /*start_from*/ ) {
     Mat desc( featuresCount, dims, CV_32FC1 );
     ts->get_rng().fill( desc, RNG::UNIFORM, minValue, maxValue );
 
-    createModel( desc );
+    createModel( desc.clone() );  // .clone() is used to simulate dangling pointers problem: https://github.com/opencv/opencv/issues/17553
 
     tempCode = checkGetPoints( desc );
     if( tempCode != cvtest::TS::OK )
index 0936462..b8df92d 100644 (file)
@@ -169,10 +169,13 @@ public:
     CV_WRAP cvflann::flann_algorithm_t getAlgorithm() const;
 
 protected:
+    bool load_(const String& filename);
+
     cvflann::flann_distance_t distType;
     cvflann::flann_algorithm_t algo;
     int featureType;
     void* index;
+    Mat features_clone;  // index may store features pointer internally for searching, so avoid dangling pointers: https://github.com/opencv/opencv/issues/17553
 };
 
 } } // namespace cv::flann
index b56578c..c871875 100644 (file)
@@ -390,14 +390,18 @@ void Index::build(InputArray _data, const IndexParams& params, flann_distance_t
     CV_INSTRUMENT_REGION();
 
     release();
+
+    // Index may reuse 'data' during search, need to keep it alive
+    features_clone = _data.getMat().clone();
+    Mat data = features_clone;
+
     algo = getParam<flann_algorithm_t>(params, "algorithm", FLANN_INDEX_LINEAR);
     if( algo == FLANN_INDEX_SAVED )
     {
-        load(_data, getParam<String>(params, "filename", String()));
+        load_(getParam<String>(params, "filename", String()));
         return;
     }
 
-    Mat data = _data.getMat();
     index = 0;
     featureType = data.type();
     distType = _distType;
@@ -462,6 +466,8 @@ void Index::release()
 {
     CV_INSTRUMENT_REGION();
 
+    features_clone.release();
+
     if( !index )
         return;
 
@@ -785,9 +791,20 @@ bool loadIndex(Index* index0, void*& index, const Mat& data, FILE* fin, const Di
 
 bool Index::load(InputArray _data, const String& filename)
 {
-    Mat data = _data.getMat();
-    bool ok = true;
     release();
+
+    // Index may reuse 'data' during search, need to keep it alive
+    features_clone = _data.getMat().clone();
+    Mat data = features_clone;
+
+    return load_(filename);
+}
+
+bool Index::load_(const String& filename)
+{
+    Mat data = features_clone;
+    bool ok = true;
+
     FILE* fin = fopen(filename.c_str(), "rb");
     if (fin == NULL)
         return false;