1 // Debugging support implementation -*- C++ -*- 2 3 // Copyright (C) 2003-2024 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file debug/helper_functions.h 26 * This file is a GNU debug extension to the Standard C++ Library. 27 */ 28 29 #ifndef _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H 30 #define _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H 1 31 32 #include <bits/move.h> // for __addressof 33 #include <bits/stl_iterator_base_types.h> // for iterator_traits, 34 // categories and _Iter_base 35 #include <bits/cpp_type_traits.h> // for __is_integer 36 37 #include <bits/stl_pair.h> // for pair 38 39 namespace __gnu_debug 40 { 41 template<typename _Iterator, typename _Sequence, typename _Category> 42 class _Safe_iterator; 43 44 #if __cplusplus >= 201103L 45 template<typename _Iterator, typename _Sequence> 46 class _Safe_local_iterator; 47 #endif 48 49 /** The precision to which we can calculate the distance between 50 * two iterators. 51 */ 52 enum _Distance_precision 53 { 54 __dp_none, // Not even an iterator type 55 __dp_equality, //< Can compare iterator equality, only 56 __dp_sign, //< Can determine equality and ordering 57 __dp_sign_max_size, //< __dp_sign and gives max range size 58 __dp_exact //< Can determine distance precisely 59 }; 60 61 template<typename _Iterator, 62 typename = typename std::__is_integer<_Iterator>::__type> 63 struct _Distance_traits 64 { 65 private: 66 typedef 67 typename std::iterator_traits<_Iterator>::difference_type _ItDiffType; 68 69 template<typename _DiffType, 70 typename = typename std::__is_void<_DiffType>::__type> 71 struct _DiffTraits 72 { typedef _DiffType __type; }; 73 74 template<typename _DiffType> 75 struct _DiffTraits<_DiffType, std::__true_type> 76 { typedef std::ptrdiff_t __type; }; 77 78 typedef typename _DiffTraits<_ItDiffType>::__type _DiffType; 79 80 public: 81 typedef std::pair<_DiffType, _Distance_precision> __type; 82 }; 83 84 template<typename _Integral> 85 struct _Distance_traits<_Integral, std::__true_type> 86 { typedef std::pair<std::ptrdiff_t, _Distance_precision> __type; }; 87 88 /** Determine the distance between two iterators with some known 89 * precision. 90 */ 91 template<typename _Iterator> 92 _GLIBCXX_CONSTEXPR 93 inline typename _Distance_traits<_Iterator>::__type 94 __get_distance(_Iterator __lhs, _Iterator __rhs, 95 std::random_access_iterator_tag) 96 { return std::make_pair(__rhs - __lhs, __dp_exact); } 97 98 template<typename _Iterator> 99 _GLIBCXX14_CONSTEXPR 100 inline typename _Distance_traits<_Iterator>::__type 101 __get_distance(_Iterator __lhs, _Iterator __rhs, 102 std::input_iterator_tag) 103 { 104 if (__lhs == __rhs) 105 return std::make_pair(0, __dp_exact); 106 107 return std::make_pair(1, __dp_equality); 108 } 109 110 template<typename _Iterator> 111 _GLIBCXX_CONSTEXPR 112 inline typename _Distance_traits<_Iterator>::__type 113 __get_distance(_Iterator __lhs, _Iterator __rhs) 114 { 115 return __gnu_debug::__get_distance(__lhs, __rhs, 116 std::__iterator_category(__lhs)); 117 } 118 119 // An arbitrary iterator pointer is not singular. 120 inline bool 121 __check_singular_aux(const void*) { return false; } 122 123 // Defined in <debug/safe_base.h> 124 bool 125 __check_singular_aux(const class _Safe_iterator_base*); 126 127 // We may have an iterator that derives from _Safe_iterator_base but isn't 128 // a _Safe_iterator. 129 template<typename _Iterator> 130 _GLIBCXX_CONSTEXPR 131 inline bool 132 __check_singular(_Iterator const& __x) 133 { 134 return ! std::__is_constant_evaluated() 135 && __gnu_debug::__check_singular_aux(std::__addressof(__x)); 136 } 137 138 /** Non-NULL pointers are nonsingular. */ 139 template<typename _Tp> 140 _GLIBCXX_CONSTEXPR 141 inline bool 142 __check_singular(_Tp* const& __ptr) 143 { return __ptr == 0; } 144 145 /** We say that integral types for a valid range, and defer to other 146 * routines to realize what to do with integral types instead of 147 * iterators. 148 */ 149 template<typename _Integral> 150 _GLIBCXX_CONSTEXPR 151 inline bool 152 __valid_range_aux(_Integral, _Integral, std::__true_type) 153 { return true; } 154 155 template<typename _Integral> 156 _GLIBCXX20_CONSTEXPR 157 inline bool 158 __valid_range_aux(_Integral, _Integral, 159 typename _Distance_traits<_Integral>::__type& __dist, 160 std::__true_type) 161 { 162 __dist = std::make_pair(0, __dp_none); 163 return true; 164 } 165 166 template<typename _InputIterator> 167 _GLIBCXX_CONSTEXPR 168 inline bool 169 __valid_range_aux(_InputIterator __first, _InputIterator __last, 170 std::input_iterator_tag) 171 { 172 // FIXME: The checks for singular iterators fail during constant eval 173 // due to PR c++/85944. e.g. PR libstdc++/109517 and PR libstdc++/109976. 174 if (std::__is_constant_evaluated()) 175 return true; 176 177 return __first == __last 178 || (!__gnu_debug::__check_singular(__first) 179 && !__gnu_debug::__check_singular(__last)); 180 } 181 182 template<typename _InputIterator> 183 _GLIBCXX_CONSTEXPR 184 inline bool 185 __valid_range_aux(_InputIterator __first, _InputIterator __last, 186 std::random_access_iterator_tag) 187 { 188 return __gnu_debug::__valid_range_aux(__first, __last, 189 std::input_iterator_tag()) 190 && __first <= __last; 191 } 192 193 /** We have iterators, so figure out what kind of iterators they are 194 * to see if we can check the range ahead of time. 195 */ 196 template<typename _InputIterator> 197 _GLIBCXX_CONSTEXPR 198 inline bool 199 __valid_range_aux(_InputIterator __first, _InputIterator __last, 200 std::__false_type) 201 { 202 return __gnu_debug::__valid_range_aux(__first, __last, 203 std::__iterator_category(__first)); 204 } 205 206 template<typename _InputIterator> 207 _GLIBCXX20_CONSTEXPR 208 inline bool 209 __valid_range_aux(_InputIterator __first, _InputIterator __last, 210 typename _Distance_traits<_InputIterator>::__type& __dist, 211 std::__false_type) 212 { 213 if (!__gnu_debug::__valid_range_aux(__first, __last, 214 std::input_iterator_tag())) 215 return false; 216 217 __dist = __gnu_debug::__get_distance(__first, __last); 218 switch (__dist.second) 219 { 220 case __dp_none: 221 break; 222 case __dp_equality: 223 if (__dist.first == 0) 224 return true; 225 break; 226 case __dp_sign: 227 case __dp_sign_max_size: 228 case __dp_exact: 229 return __dist.first >= 0; 230 } 231 232 // Can't tell so assume it is fine. 233 return true; 234 } 235 236 /** Don't know what these iterators are, or if they are even 237 * iterators (we may get an integral type for InputIterator), so 238 * see if they are integral and pass them on to the next phase 239 * otherwise. 240 */ 241 template<typename _InputIterator> 242 _GLIBCXX20_CONSTEXPR 243 inline bool 244 __valid_range(_InputIterator __first, _InputIterator __last, 245 typename _Distance_traits<_InputIterator>::__type& __dist) 246 { 247 typedef typename std::__is_integer<_InputIterator>::__type _Integral; 248 return __gnu_debug::__valid_range_aux(__first, __last, __dist, 249 _Integral()); 250 } 251 252 template<typename _Iterator, typename _Sequence, typename _Category> 253 bool 254 __valid_range(const _Safe_iterator<_Iterator, _Sequence, _Category>&, 255 const _Safe_iterator<_Iterator, _Sequence, _Category>&, 256 typename _Distance_traits<_Iterator>::__type&); 257 258 #if __cplusplus >= 201103L 259 template<typename _Iterator,typename _Sequence> 260 bool 261 __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>&, 262 const _Safe_local_iterator<_Iterator, _Sequence>&, 263 typename _Distance_traits<_Iterator>::__type&); 264 #endif 265 266 template<typename _InputIterator> 267 _GLIBCXX14_CONSTEXPR 268 inline bool 269 __valid_range(_InputIterator __first, _InputIterator __last) 270 { 271 typedef typename std::__is_integer<_InputIterator>::__type _Integral; 272 return __gnu_debug::__valid_range_aux(__first, __last, _Integral()); 273 } 274 275 template<typename _Iterator, typename _Sequence, typename _Category> 276 bool 277 __valid_range(const _Safe_iterator<_Iterator, _Sequence, _Category>&, 278 const _Safe_iterator<_Iterator, _Sequence, _Category>&); 279 280 #if __cplusplus >= 201103L 281 template<typename _Iterator, typename _Sequence> 282 bool 283 __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>&, 284 const _Safe_local_iterator<_Iterator, _Sequence>&); 285 #endif 286 287 // Fallback method, always ok. 288 template<typename _InputIterator, typename _Size> 289 _GLIBCXX_CONSTEXPR 290 inline bool 291 __can_advance(_InputIterator, _Size) 292 { return true; } 293 294 template<typename _Iterator, typename _Sequence, typename _Category, 295 typename _Size> 296 bool 297 __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>&, 298 _Size); 299 300 template<typename _InputIterator, typename _Diff> 301 _GLIBCXX_CONSTEXPR 302 inline bool 303 __can_advance(_InputIterator, const std::pair<_Diff, _Distance_precision>&, int) 304 { return true; } 305 306 template<typename _Iterator, typename _Sequence, typename _Category, 307 typename _Diff> 308 bool 309 __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>&, 310 const std::pair<_Diff, _Distance_precision>&, int); 311 312 /** Helper function to extract base iterator of random access safe iterator 313 * in order to reduce performance impact of debug mode. Limited to random 314 * access iterator because it is the only category for which it is possible 315 * to check for correct iterators order in the __valid_range function 316 * thanks to the < operator. 317 */ 318 template<typename _Iterator> 319 _GLIBCXX_CONSTEXPR 320 inline _Iterator 321 __base(_Iterator __it) 322 { return __it; } 323 324 #if __cplusplus < 201103L 325 template<typename _Iterator> 326 struct _Unsafe_type 327 { typedef _Iterator _Type; }; 328 #endif 329 330 /* Remove debug mode safe iterator layer, if any. */ 331 template<typename _Iterator> 332 _GLIBCXX_CONSTEXPR 333 inline _Iterator 334 __unsafe(_Iterator __it) 335 { return __it; } 336 } 337 338 #endif 339