Skip to content

b2 does not build with libstdc++ + -D_GLIBCXX_DEBUG because list_cref::iterator advertises itself as random access but does not implement operator<= #464

@sliedes

Description

@sliedes

Make sure you completed the following tasks

Environment and version details

  • Operating System+version: NixOS unstable
  • Compiler+version: gcc 14.3.0
  • Shell: bash
  • B2 Version: boost 1.87.0; however the code in this repo master seems identical

Brief problem description

For hardening and catching bugs, libstdc++ supports a -D_GLIBCXX_DEBUG preprocessor define, in functionality probably similar to MSVC debug iterators. It adds extra checks to STL containers and iterators.

In this case because list_cref::iterator advertises being a random access iterator, libstdc++ goes on to check some properties:

using iterator_category = std::random_access_iterator_tag;

Unfortunately, list_cref::iterator is not a random access iterator, causing this build failure:

> g++ -x c++ -std=c++11 -pthread -O2 -s -DNDEBUG bindjam.cpp builtins.cpp class.cpp command.cpp compile.cpp constants.cpp cwd.cpp debug.cpp debugger.cpp events.cpp execcmd.cpp execnt.cpp execunix.cpp filent.cpp filesys.cpp fileunix.cpp frames.cpp function.cpp glob.cpp hash.cpp hcache.cpp hdrmacro.cpp headers.cpp jam_strings.cpp jam.cpp jamgram.cpp lists.cpp make.cpp make1.cpp md5.cpp mem.cpp modules.cpp native.cpp option.cpp output.cpp parse.cpp pathnt.cpp pathsys.cpp pathunix.cpp regexp.cpp rules.cpp scan.cpp search.cpp startup.cpp tasks.cpp timestamp.cpp value.cpp variable.cpp w32_getreg.cpp mod_command_db.cpp mod_db.cpp mod_jam_builtin.cpp mod_jam_class.cpp mod_jam_errors.cpp mod_jam_modules.cpp mod_order.cpp mod_path.cpp mod_property_set.cpp mod_regex.cpp mod_sequence.cpp mod_set.cpp mod_string.cpp mod_summary.cpp mod_sysinfo.cpp mod_version.cpp -o b2
In file included from /nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/stl_iterator.h:32,
                 from /nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/bits/stl_iterator.h:3024,
                 from /nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/bits/stl_algobase.h:67,
                 from /nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/bits/stl_uninitialized.h:63,
                 from /nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/memory:69,
                 from mem.h:14,
                 from jam.h:537,
                 from lists.h:48,
                 from frames.h:12,
                 from function.h:13,
                 from native.h:11,
                 from mod_sequence.cpp:8:
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/helper_functions.h: In instantiation of ‘constexpr bool __gnu_debug::__valid_range_aux(_InputIterator, _InputIterator, std::random_access_iterator_tag) [with _InputIterator = b2::list_cref::iterator]’:
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/helper_functions.h:202:44:   required from ‘constexpr bool __gnu_debug::__valid_range_aux(_InputIterator, _InputIterator, std::__false_type) [with _InputIterator = b2::list_cref::iterator]’
  202 |       return __gnu_debug::__valid_range_aux(__first, __last,
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
  203 |                                             std::__iterator_category(__first));
      |                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/helper_functions.h:272:44:   required from ‘bool __gnu_debug::__valid_range(_InputIterator, _InputIterator) [with _InputIterator = b2::list_cref::iterator]’
  272 |       return __gnu_debug::__valid_range_aux(__first, __last, _Integral());
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/bits/stl_algo.h:655:7:   required from ‘_OIter std::copy_if(_IIter, _IIter, _OIter, _Predicate) [with _IIter = b2::list_cref::iterator; _OIter = back_insert_iterator<b2::list_ref>; _Predicate = stable_unique(b2::list_cref)::<lambda({anonymous}::list_value_cref)>]’
  655 |       __glibcxx_requires_valid_range(__first, __last);
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mod_sequence.cpp:135:14:   required from here
  135 |         std::copy_if(values.begin(), values.end(), std::back_inserter(result),
      |         ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  136 |                 [&unique_values](
      |                 ~~~~~~~~~~~~~~~~~
  137 |                         list_value_cref ptr) { return unique_values.insert(ptr).second; });
      |                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/helper_functions.h:190:20: error: no match for ‘operator<=’ (operand types are ‘b2::list_cref::iterator’ and ‘b2::list_cref::iterator’)
  190 |         && __first <= __last;
      |            ~~~~~~~~^~~~~~~~~
In file included from /nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/stl_iterator.h:32,
                 from /nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/bits/stl_iterator.h:3024,
                 from /nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/string:48,
                 from bind.h:12,
                 from mod_set.h:12,
                 from mod_set.cpp:7:
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/helper_functions.h: In instantiation of ‘constexpr bool __gnu_debug::__valid_range_aux(_InputIterator, _InputIterator, std::random_access_iterator_tag) [with _InputIterator = b2::list_cref::iterator]’:
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/helper_functions.h:202:44:   required from ‘constexpr bool __gnu_debug::__valid_range_aux(_InputIterator, _InputIterator, std::__false_type) [with _InputIterator = b2::list_cref::iterator]’
  202 |       return __gnu_debug::__valid_range_aux(__first, __last,
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
  203 |                                             std::__iterator_category(__first));
      |                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/helper_functions.h:272:44:   required from ‘bool __gnu_debug::__valid_range(_InputIterator, _InputIterator) [with _InputIterator = b2::list_cref::iterator]’
  272 |       return __gnu_debug::__valid_range_aux(__first, __last, _Integral());
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/functions.h:63:7:   required from ‘_InputIterator __gnu_debug::__check_valid_range(const _InputIterator&, const _InputIterator&, const char*, unsigned int, const char*) [with _InputIterator = b2::list_cref::iterator]’
   63 |       __glibcxx_check_valid_range_at(__first, __last,
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/unordered_set:128:5:   required from ‘std::__debug::unordered_set<_Key, _Hash, _Pred, _Allocator>::unordered_set(_InputIterator, _InputIterator, size_type, const hasher&, const key_equal&, const allocator_type&) [with _InputIterator = b2::list_cref::iterator; _Value = b2::value_ref; _Hash = b2::value_ref::hash_function; _Pred = b2::value_ref::equal_function; _Alloc = std::allocator<b2::value_ref>; size_type = long unsigned int; hasher = b2::value_ref::hash_function; key_equal = b2::value_ref::equal_function; allocator_type = std::allocator<b2::value_ref>]’
  128 |                   __glibcxx_check_valid_constructor_range(__first, __last)),
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mod_set.cpp:38:37:   required from here
   38 |         value_set rhs { b.begin(), b.end() };
      |                                            ^
/nix/store/jyphzc03k61s72s290l97npk0p9daspz-gcc-14.3.0/include/c++/14.3.0/debug/helper_functions.h:190:20: error: no match for ‘operator<=’ (operand types are ‘b2::list_cref::iterator’ and ‘b2::list_cref::iterator’)
  190 |         && __first <= __last;
      |            ~~~~~~~~^~~~~~~~~

As can be seen, libstdc++ trusts the tag and expects the iterator to have an operator<=.

I can see in the source code that this has already been worked around for MSVC by adding an operator<.

friend inline bool operator<(const iterator & a, const iterator & b)

Of course, I believe ideally the iterator should either be a random access iterator or not advertise itself as one. Now, I believe the minimal fix for libstdc++ debug mode would be to implement an operator<=.

Steps to reproduce the issue

Try to build b2 with -D_GLIBCXX_DEBUG.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

Status

🔖 Ready

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions