From 5494a86ea9f10322f259b08467e83e59b0d6d237 Mon Sep 17 00:00:00 2001 From: Jose Luis Blanco-Claraco Date: Fri, 16 Jun 2023 00:51:19 +0200 Subject: [PATCH] FIX: Avoid segfault if saving an empty index Closes #205 --- CHANGELOG.md | 2 ++ examples/saveload_example.cpp | 10 ++++++++++ include/nanoflann.hpp | 20 +++++++++++--------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86d92299..c2d63a1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ nanoflann 1.5.0: UNRELEASED - Add examples with GUI (requires [mrpt-gui](https://docs.mrpt.org/reference/latest/group_mrpt_gui_grp.html)): - nanoflann_gui_example_R3: Radius search on R³ Euclidean space. - nanoflann_gui_example_bearings: NN search on non-Euclidean spaces. + * BUGFIXES: + - Avoid segfault if saving an empty index (Closes [#205](https://github.com/jlblancoc/nanoflann/issues/205)). nanoflann 1.4.3: Released Jul 24, 2022 * Added flag SkipInitialBuildIndex to allow not wasting time building a tree when it will be loaded from a file later on ([PR #171](https://github.com/jlblancoc/nanoflann/pull/171)). diff --git a/examples/saveload_example.cpp b/examples/saveload_example.cpp index b5d62e8c..bfb7f090 100644 --- a/examples/saveload_example.cpp +++ b/examples/saveload_example.cpp @@ -96,6 +96,16 @@ void kdtree_save_load_demo(const size_t N) std::cout << "ret_index=" << ret_index << " out_dist_sqr=" << out_dist_sqr << std::endl; } + + // Stress test: try to save an empty index + { + PointCloud emptyCloud; + my_kd_tree_t index(3 /*dim*/, emptyCloud); + std::ofstream f("index2.bin", std::ofstream::binary); + if (f.bad()) throw std::runtime_error("Error writing index file!"); + index.saveIndex(f); + f.close(); + } } int main() diff --git a/include/nanoflann.hpp b/include/nanoflann.hpp index 305b25a4..c2c80fd8 100644 --- a/include/nanoflann.hpp +++ b/include/nanoflann.hpp @@ -418,7 +418,9 @@ struct L1_Adaptor /* Process last 0-3 components. Not needed for standard vector lengths. */ while (a < last) - { result += std::abs(*a++ - data_source.kdtree_get_pt(b_idx, d++)); } + { + result += std::abs(*a++ - data_source.kdtree_get_pt(b_idx, d++)); + } return result; } @@ -1362,7 +1364,7 @@ class KDTreeBaseClass save_value(stream, obj.root_bbox_); save_value(stream, obj.leaf_max_size_); save_value(stream, obj.vAcc_); - save_tree(obj, stream, obj.root_node_); + if (obj.root_node_) save_tree(obj, stream, obj.root_node_); } /** Loads a previous index from a binary file. @@ -1784,8 +1786,7 @@ class KDTreeSingleIndexAdaptor } /* Call recursively to search next level down. */ - if (!searchLevel( - result_set, vec, bestChild, mindist, dists, epsError)) + if (!searchLevel(result_set, vec, bestChild, mindist, dists, epsError)) { // the resultset doesn't want to receive any more points, we're done // searching! @@ -1793,7 +1794,7 @@ class KDTreeSingleIndexAdaptor } DistanceType dst = dists[idx]; - mindist = mindist + cut_dist - dst; + mindist = mindist + cut_dist - dst; dists[idx] = cut_dist; if (mindist * epsError <= result_set.worstDist()) { @@ -2217,12 +2218,11 @@ class KDTreeSingleIndexDynamicAdaptor_ searchLevel(result_set, vec, bestChild, mindist, dists, epsError); DistanceType dst = dists[idx]; - mindist = mindist + cut_dist - dst; + mindist = mindist + cut_dist - dst; dists[idx] = cut_dist; if (mindist * epsError <= result_set.worstDist()) { - searchLevel( - result_set, vec, otherChild, mindist, dists, epsError); + searchLevel(result_set, vec, otherChild, mindist, dists, epsError); } dists[idx] = dst; } @@ -2440,7 +2440,9 @@ class KDTreeSingleIndexDynamicAdaptor const SearchParameters& searchParams = {}) const { for (size_t i = 0; i < treeCount_; i++) - { index_[i].findNeighbors(result, &vec[0], searchParams); } + { + index_[i].findNeighbors(result, &vec[0], searchParams); + } return result.full(); } };