[Boost-bugs] [Boost C++ Libraries] #12578: Crash with boost::filesystem's directory_iterator and recursive_directory_iterator

Subject: [Boost-bugs] [Boost C++ Libraries] #12578: Crash with boost::filesystem's directory_iterator and recursive_directory_iterator
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2016-11-03 19:08:29


#12578: Crash with boost::filesystem's directory_iterator and
recursive_directory_iterator
-----------------------+------------------------------
 Reporter: anonymous | Type: Bugs
   Status: new | Milestone: To Be Determined
Component: None | Version: Boost 1.61.0
 Severity: Problem | Keywords:
-----------------------+------------------------------
 I have a simple example using `recursive_directory_iterator` that crashes,
 but it also crashes with `directory_iterator`. I am aware from the
 documentation that "[t]he practical consequence of not preserving equality
 is that directory iterators can only be used for single-pass algorithms",
 but I don't see why my use here would invoke undefined behavior since I
 make a copy of a `const` iterator.
 {{{
 #!div style="font-size: 80%"
   {{{#!cpp
 #include <boost/filesystem.hpp>
 #include <boost/range/iterator_range.hpp>
 #include <iostream>

 namespace fs = boost::filesystem;

 int main()
 {
   try
   {
     const auto iter = fs::recursive_directory_iterator{ "." };
     std::cout << std::distance( iter, {} ) << "\n";
     for( const auto& entry : boost::make_iterator_range(
                                iter, // CRASH!
                                {} ) )
     {
       std::cout << entry << "\n";
     }
   }
   catch( const std::exception& e )
   {
     std::cerr << e.what() << "\n";
   }
   catch( ... )
   {
     std::cerr << "Unknown exception.\n";
   }
 }
   }}}
 }}}
 This crashes on several compilers, Windows and Linux, and multiple
 versions of Boost.^[#crash (a)]^

 Note that `iter` is `const`. I can workaround this by (1) replacing
 `iter```^[#replaceIter (b)]^ on the line marked "CRASH" with
 `fs::recursive_directory_iterator{ "." }` or (2) deleting the call to
 `std::distance()` just before the for loop or by changing its
 arguments^[#replaceDist (c)]^. Either of these have the effect of not
 advancing a copy of `iter` to the end.

 I suspect this has something to do with the copy of `iter` made by
 `std::distance()` and `boost::make_iterator_range()` still being secretly
 connected to the internal state of `iter`, though it is a `const` iterator
 from which a deep copy was supposed to be made. It also happens with
 experimental::filesystem^[#expFS (d)]^ and multiple versions of Boost (at
 least 1.61.0 and 1.55.0).

 This same problem can also be seen in other scenarios such as iterating
 over a directory range twice^[#twice (e)]^ or any other use of a recursive
 directory iterator which has had a copy made and advanced to end.

 I asked about this on the Boost Users list^[#user (f)]^, but got no reply.

 '''Links'''
 * [=#crash (a)] See, e.g., the crash on Coliru with gcc: coliru.stacked-
 crooked.com/a/15c4a731100d25f2
 * [=#replaceIter (b)] coliru.stacked-crooked.com/a/b37f94ebc809fa65
 * [=#replaceDist (c)] coliru.stacked-crooked.com/a/17277df962ab5989
 * [=#expFS (d)] coliru.stacked-crooked.com/a/8e83f5c7e2adfe90
 * [=#twice (e)] coliru.stacked-crooked.com/a/0bfab95a513ebed8
 * [=#user (f)] lists.boost.org/boost-users/2016/10/86840.php

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/12578>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:20 UTC