Home | History | Annotate | Download | only in debug
      1 /*
      2  *
      3  * Copyright (c) 1997
      4  * Moscow Center for SPARC Technology
      5  *
      6  * Copyright (c) 1999
      7  * Boris Fomitchev
      8  *
      9  * This material is provided "as is", with absolutely no warranty expressed
     10  * or implied. Any use is at your own risk.
     11  *
     12  * Permission to use or copy this software for any purpose is hereby granted
     13  * without fee, provided the above notices are retained on all copies.
     14  * Permission to modify the code and to distribute modified code is granted,
     15  * provided the above notices are retained, and a notice that the code was
     16  * modified is included with the above copyright notice.
     17  *
     18  */
     19 
     20 #ifndef _STLP_DEBUG_H
     21 #define _STLP_DEBUG_H
     22 
     23 #if (defined (_STLP_DEBUG) || defined (_STLP_DEBUG_ALLOC)) && \
     24     !defined (_STLP_ASSERTIONS)
     25 #  define _STLP_ASSERTIONS 1
     26 #endif
     27 
     28 #if defined (_STLP_ASSERTIONS)
     29 
     30 #  if !defined (_STLP_FILE__)
     31 #    define _STLP_FILE__ __FILE__
     32 #  endif
     33 
     34 _STLP_BEGIN_NAMESPACE
     35 
     36 _STLP_MOVE_TO_PRIV_NAMESPACE
     37 
     38 enum {
     39   //General errors
     40   _StlFormat_ERROR_RETURN,
     41   _StlFormat_ASSERTION_FAILURE,
     42   _StlFormat_VERBOSE_ASSERTION_FAILURE,
     43   _StlMsg_INVALID_ARGUMENT,
     44   //Container/Iterator related errors
     45   _StlMsg_INVALID_CONTAINER,
     46   _StlMsg_EMPTY_CONTAINER,
     47   _StlMsg_ERASE_PAST_THE_END,
     48   _StlMsg_OUT_OF_BOUNDS,
     49   _StlMsg_NOT_OWNER,
     50   _StlMsg_SHOULD_NOT_OWNER,
     51   _StlMsg_INVALID_ITERATOR,
     52   _StlMsg_INVALID_LEFTHAND_ITERATOR,
     53   _StlMsg_INVALID_RIGHTHAND_ITERATOR,
     54   _StlMsg_DIFFERENT_OWNERS     ,
     55   _StlMsg_NOT_DEREFERENCEABLE  ,
     56   _StlMsg_INVALID_RANGE        ,
     57   _StlMsg_NOT_IN_RANGE_1       ,
     58   _StlMsg_NOT_IN_RANGE_2       ,
     59   _StlMsg_INVALID_ADVANCE      ,
     60   _StlMsg_SINGULAR_ITERATOR    ,
     61   //Bad predicate for sorting
     62   _StlMsg_INVALID_STRICT_WEAK_PREDICATE,
     63   _StlMsg_INVALID_EQUIVALENT_PREDICATE,
     64   // debug alloc messages
     65   _StlMsg_DBA_DELETED_TWICE    ,
     66   _StlMsg_DBA_NEVER_ALLOCATED  ,
     67   _StlMsg_DBA_TYPE_MISMATCH    ,
     68   _StlMsg_DBA_SIZE_MISMATCH    ,
     69   _StlMsg_DBA_UNDERRUN         ,
     70   _StlMsg_DBA_OVERRUN          ,
     71   // auto_ptr messages
     72   _StlMsg_AUTO_PTR_NULL    ,
     73   //Memory alignent message
     74   _StlMsg_WRONG_MEMORY_ALIGNMENT,
     75   _StlMsg_UNKNOWN
     76   /* _StlMsg_MAX */
     77 };
     78 
     79 /* have to hardcode that ;() */
     80 #  define _StlMsg_MAX 31
     81 
     82 class __owned_link;
     83 class __owned_list;
     84 
     85 #  if defined (_STLP_DEBUG_MODE_THROWS)
     86 #    define _STLP_MESSAGE_NORETURN _STLP_FUNCTION_THROWS
     87 #  else
     88 #    define _STLP_MESSAGE_NORETURN
     89 #  endif
     90 
     91 template <class _Dummy>
     92 class __stl_debug_engine {
     93 public:
     94   // Basic routine to report any debug message
     95   // Use _STLP_DEBUG_MESSAGE to override
     96   static void _STLP_MESSAGE_NORETURN _STLP_CALL _Message(const char * format_str, ...);
     97 
     98   // Micsellanous function to report indexed error message
     99   static void _STLP_CALL  _IndexedError(int __ind, const char* __f, int __l);
    100 
    101   // Basic assertion report mechanism.
    102   // Reports failed assertion via __stl_debug_message and calls _Terminate
    103   // if _STLP_DEBUG_TERMINATE is specified, calls __stl_debug_terminate instead
    104   static void _STLP_CALL  _Assert(const char* __expr, const char* __f, int __l);
    105 
    106   // The same, with additional diagnostics
    107   static void _STLP_CALL  _VerboseAssert(const char* __expr, int __error_ind, const char* __f, int __l);
    108 
    109   // If exceptions are present, sends unique exception
    110   // If not, calls _STLP_ABORT() to terminate
    111   // Use _STLP_DEBUG_TERMINATE to override
    112   static void _STLP_CALL  _Terminate();
    113 
    114 #  if defined (_STLP_DEBUG)
    115   // owned_list/link delegate non-inline functions here
    116 
    117   static bool _STLP_CALL  _Check_same_owner( const __owned_link& __i1,
    118                                              const __owned_link& __i2);
    119   static bool _STLP_CALL  _Check_same_or_null_owner( const __owned_link& __i1,
    120                                                      const __owned_link& __i2);
    121   static bool _STLP_CALL  _Check_if_owner( const __owned_list*, const __owned_link&);
    122 
    123   static bool _STLP_CALL  _Check_if_not_owner( const __owned_list*, const __owned_link&);
    124 
    125   static void _STLP_CALL  _Verify(const __owned_list*);
    126 
    127   static void _STLP_CALL  _Swap_owners(__owned_list&, __owned_list&);
    128 
    129   static void _STLP_CALL  _Invalidate_all(__owned_list*);
    130 
    131   static void _STLP_CALL  _Set_owner(__owned_list& /*src*/, __owned_list& /*dst*/);
    132 
    133   static void _STLP_CALL  _Stamp_all(__owned_list*, __owned_list*);
    134 
    135   static void _STLP_CALL  _M_detach(__owned_list*, __owned_link*);
    136 
    137   static void _STLP_CALL  _M_attach(__owned_list*, __owned_link*);
    138 
    139   // accessor : check and get pointer to the container
    140   static void* _STLP_CALL  _Get_container_ptr(const __owned_link*);
    141 #  endif
    142 
    143   // debug messages and formats
    144   static const char* _Message_table[_StlMsg_MAX];
    145 };
    146 
    147 #  undef _STLP_MESSAGE_NORETURN
    148 
    149 #  if defined (_STLP_USE_TEMPLATE_EXPORT)
    150 _STLP_EXPORT_TEMPLATE_CLASS __stl_debug_engine<bool>;
    151 #  endif
    152 
    153 typedef __stl_debug_engine<bool> __stl_debugger;
    154 
    155 _STLP_MOVE_TO_STD_NAMESPACE
    156 
    157 _STLP_END_NAMESPACE
    158 
    159 #  if !defined (_STLP_ASSERT)
    160 #    define _STLP_ASSERT(expr) \
    161        if (!(expr)) { _STLP_PRIV __stl_debugger::_Assert( # expr, _STLP_FILE__, __LINE__); }
    162 #  endif
    163 
    164 #else
    165 #  define _STLP_ASSERT(expr)
    166 #endif
    167 
    168 // this section is for _STLP_DEBUG only
    169 #if defined (_STLP_DEBUG)
    170 
    171 #  if !defined (_STLP_VERBOSE_ASSERT)
    172 // fbp : new form not requiring ";"
    173 #    define _STLP_VERBOSE_ASSERT(expr, __diag_num) \
    174        if (!(expr)) { _STLP_PRIV __stl_debugger::_VerboseAssert\
    175                                ( # expr,  _STLP_PRIV __diag_num, _STLP_FILE__, __LINE__ ); \
    176           }
    177 #  endif
    178 
    179 #  define _STLP_DEBUG_CHECK(expr) _STLP_ASSERT(expr)
    180 
    181 #  if (_STLP_DEBUG_LEVEL == _STLP_STANDARD_DBG_LEVEL)
    182 #    define _STLP_STD_DEBUG_CHECK(expr) _STLP_DEBUG_CHECK(expr)
    183 #  else
    184 #    define _STLP_STD_DEBUG_CHECK(expr)
    185 #  endif
    186 
    187 #  if !defined (_STLP_VERBOSE_RETURN)
    188 #    define _STLP_VERBOSE_RETURN(__expr,__diag_num) if (!(__expr)) { \
    189          _STLP_PRIV __stl_debugger::_IndexedError(__diag_num, _STLP_FILE__ , __LINE__); \
    190          return false; }
    191 #  endif
    192 
    193 #  if !defined (_STLP_VERBOSE_RETURN_0)
    194 #    define _STLP_VERBOSE_RETURN_0(__expr,__diag_num) if (!(__expr)) { \
    195          _STLP_PRIV __stl_debugger::_IndexedError(__diag_num, _STLP_FILE__, __LINE__); \
    196          return 0; }
    197 #  endif
    198 
    199 #  ifndef _STLP_INTERNAL_THREADS_H
    200 #    include <stl/_threads.h>
    201 #  endif
    202 
    203 #  ifndef _STLP_INTERNAL_ITERATOR_BASE_H
    204 #    include <stl/_iterator_base.h>
    205 #  endif
    206 
    207 #  ifndef _STLP_TYPE_TRAITS_H
    208 #    include <stl/type_traits.h>
    209 #  endif
    210 
    211 _STLP_BEGIN_NAMESPACE
    212 
    213 _STLP_MOVE_TO_PRIV_NAMESPACE
    214 
    215 /*
    216  * Special debug iterator traits having an additionnal static member
    217  * method _Check. It is used by the slist debug implementation to check
    218  * the special before_begin iterator.
    219  */
    220 template <class _Traits>
    221 struct _DbgTraits : _Traits {
    222   typedef _DbgTraits<typename _Traits::_ConstTraits> _ConstTraits;
    223   typedef _DbgTraits<typename _Traits::_NonConstTraits> _NonConstTraits;
    224 
    225   template <class _Iterator>
    226   static bool _Check(const _Iterator&) {return true;}
    227 };
    228 
    229 //=============================================================
    230 template <class _Iterator>
    231 inline bool  _STLP_CALL __valid_range(const _Iterator& __i1 ,const _Iterator& __i2,
    232                                       const random_access_iterator_tag&)
    233 { return (__i1 < __i2) || (__i1 == __i2); }
    234 
    235 template <class _Iterator>
    236 inline bool  _STLP_CALL __valid_range(const _Iterator& __i1 ,const _Iterator& __i2,
    237                                       const bidirectional_iterator_tag&) {
    238   // check if comparable
    239   bool __dummy(__i1==__i2);
    240   return (__dummy==__dummy);
    241 }
    242 
    243 template <class _Iterator>
    244 inline bool  _STLP_CALL __valid_range(const _Iterator& __i1 ,const _Iterator& __i2,
    245                                       const forward_iterator_tag&) {
    246   // check if comparable
    247   bool __dummy(__i1==__i2);
    248   return (__dummy==__dummy);
    249 }
    250 
    251 template <class _Iterator>
    252 inline bool  _STLP_CALL __valid_range(const _Iterator&,const _Iterator&,
    253                                       const input_iterator_tag&)
    254 { return true; }
    255 
    256 template <class _Iterator>
    257 inline bool  _STLP_CALL __valid_range(const _Iterator&,const _Iterator&,
    258                                       const output_iterator_tag&)
    259 { return true; }
    260 
    261 template <class _Iterator>
    262 inline bool _STLP_CALL __valid_range(const _Iterator& __i1, const _Iterator& __i2)
    263 { return __valid_range(__i1,__i2,_STLP_ITERATOR_CATEGORY(__i1, _Iterator)); }
    264 
    265 // Note : that means in range [i1, i2].
    266 template <class _Iterator>
    267 inline bool  _STLP_CALL stlp_in_range(const _Iterator& _It,
    268                                       const _Iterator& __i1, const _Iterator& __i2)
    269 { return __valid_range(__i1,_It) && __valid_range(_It,__i2); }
    270 
    271 template <class _Iterator>
    272 inline bool  _STLP_CALL stlp_in_range(const _Iterator& __first, const _Iterator& __last,
    273                                       const _Iterator& __start, const _Iterator& __finish)
    274 { return __valid_range(__first,__last) && __valid_range(__start,__first) && __valid_range(__last,__finish); }
    275 
    276 //==========================================================
    277 class _STLP_CLASS_DECLSPEC __owned_link {
    278 public:
    279   // Note: This and the following special defines for compiling under Windows CE under ARM
    280   // is needed for correctly using _STLP_DEBUG mode. This comes from a bug in the ARM
    281   // compiler where checked iterators that are passed by value call _M_attach with the wrong
    282   // this pointer and calling _M_detach can't find the correct pointer to the __owned_link.
    283   // This is circumvented by managing a _M_self pointer that points to the correct value.
    284   // Ugly but works.
    285 #if defined(_STLP_WCE) && defined(_ARM_)
    286   __owned_link() : _M_self(this), _M_owner(0) {}
    287   __owned_link(const __owned_list* __c) : _M_self(this), _M_owner(0), _M_next(0)
    288   { __stl_debugger::_M_attach(__CONST_CAST(__owned_list*,__c), this); }
    289   __owned_link(const __owned_link& __rhs): _M_self(this), _M_owner(0)
    290   { __stl_debugger::_M_attach(__CONST_CAST(__owned_list*,__rhs._M_owner), this); }
    291 #else
    292   __owned_link() : _M_owner(0) {}
    293   __owned_link(const __owned_list* __c) : _M_owner(0), _M_next(0)
    294   { __stl_debugger::_M_attach(__CONST_CAST(__owned_list*,__c), this); }
    295   __owned_link(const __owned_link& __rhs): _M_owner(0)
    296   { __stl_debugger::_M_attach(__CONST_CAST(__owned_list*,__rhs._M_owner), this); }
    297 #endif
    298   __owned_link& operator=(const __owned_link& __rhs) {
    299     __owned_list* __new_owner = __CONST_CAST(__owned_list*,__rhs._M_owner);
    300     __owned_list* __old_owner = _M_owner;
    301     if ( __old_owner != __new_owner ) {
    302       __stl_debugger::_M_detach(__old_owner, this);
    303       __stl_debugger::_M_attach(__new_owner, this);
    304     }
    305     return *this;
    306   }
    307 #if defined(_STLP_WCE) && defined(_ARM_)
    308   ~__owned_link() {
    309     __stl_debugger::_M_detach(_M_owner, _M_self);
    310     _Invalidate();
    311   }
    312 #else
    313   ~__owned_link() {
    314     __stl_debugger::_M_detach(_M_owner, this);
    315     _Invalidate();
    316   }
    317 #endif
    318 
    319   const __owned_list* _Owner() const { return _M_owner; }
    320   __owned_list* _Owner() { return _M_owner; }
    321   void _Set_owner(const __owned_list* __o) { _M_owner= __CONST_CAST(__owned_list*,__o); }
    322   bool _Valid() const { return _M_owner != 0; }
    323   void _Invalidate() { _M_owner = 0; _M_next = 0; }
    324   void _Link_to_self() { _M_next = 0; }
    325 
    326   __owned_link* _Next() { return _M_next; }
    327   const __owned_link* _Next() const { return _M_next; }
    328 
    329 public:
    330 #if defined(_STLP_WCE) && defined(_ARM_)
    331   __owned_link* _M_self;
    332 #endif
    333 
    334   __owned_list* _M_owner;
    335   __owned_link* _M_next;
    336 };
    337 
    338 
    339 class _STLP_CLASS_DECLSPEC __owned_list {
    340 public:
    341   __owned_list(void* __o) {
    342     //    fprintf(stderr, "__owned_list(): %p\n",(void*)this);
    343     _M_node._M_owner = __REINTERPRET_CAST(__owned_list*,__o);
    344     _M_node._M_next = 0;
    345   }
    346   ~__owned_list() {
    347     //    fprintf(stderr, "~__owned_list(): %p\n",(void*)this);
    348     _Invalidate_all();
    349     // that prevents detach
    350     _M_node._Invalidate();
    351   }
    352   const void* _Owner() const { return (const void*)_M_node._M_owner; }
    353   void* _Owner() { return (void*)_M_node._M_owner; }
    354   bool  _Valid() const { return _M_node._M_owner != 0; }
    355   void _Invalidate() { _M_node._M_owner = 0; }
    356 
    357   __owned_link* _First() { return _M_node._Next(); }
    358   __owned_link* _Last() { return 0 ; }
    359 
    360   const __owned_link* _First() const { return (__owned_link*)_M_node._M_next; }
    361   const __owned_link* _Last() const { return 0 ;}
    362 
    363   void _Verify() const { __stl_debugger::_Verify(this); }
    364   void _Swap_owners(__owned_list& __y) { __stl_debugger::_Swap_owners(*this, __y); }
    365   void _Invalidate_all() { __stl_debugger::_Invalidate_all(this); }
    366   void _Set_owner(__owned_list& __y) { __stl_debugger::_Set_owner(*this, __y); }
    367 
    368   mutable __owned_link _M_node;
    369   mutable _STLP_mutex  _M_lock;
    370 
    371 private:
    372   // should never be called, should be left not implemented,
    373   // but some compilers complain about it ;(
    374   __owned_list(const __owned_list&){}
    375   __owned_list& operator = (const __owned_list&) { return *this; }
    376 
    377   friend class __owned_link;
    378   friend class __stl_debug_engine<bool>;
    379 };
    380 
    381 
    382 //==========================================================
    383 
    384 // forward declaratioins
    385 
    386 template <class _Iterator>
    387 bool _STLP_CALL __check_range(const _Iterator&, const _Iterator&);
    388 template <class _Iterator>
    389 bool _STLP_CALL __check_range(const _Iterator&,
    390                               const _Iterator&, const _Iterator&);
    391 template <class _Iterator>
    392 bool _STLP_CALL __check_range(const _Iterator&, const _Iterator& ,
    393                               const _Iterator&, const _Iterator& );
    394 template <class _Tp>
    395 bool _STLP_CALL __check_ptr_range(const _Tp*, const _Tp*);
    396 
    397 template <class _Iterator>
    398 void _STLP_CALL __invalidate_range(const __owned_list* __base,
    399                                    const _Iterator& __first,
    400                                    const _Iterator& __last);
    401 
    402 template <class _Iterator>
    403 void _STLP_CALL __invalidate_iterator(const __owned_list* __base,
    404                                       const _Iterator& __it);
    405 
    406 template <class _Iterator>
    407 void _STLP_CALL __change_range_owner(const _Iterator& __first,
    408                                      const _Iterator& __last,
    409                                      const __owned_list* __dst);
    410 
    411 template <class _Iterator>
    412 void  _STLP_CALL __change_ite_owner(const _Iterator& __it,
    413                                     const __owned_list* __dst);
    414 
    415 //============================================================
    416 inline bool _STLP_CALL
    417 __check_same_owner(const __owned_link& __i1, const __owned_link& __i2)
    418 { return __stl_debugger::_Check_same_owner(__i1,__i2); }
    419 
    420 inline bool _STLP_CALL
    421 __check_same_or_null_owner(const __owned_link& __i1, const __owned_link& __i2)
    422 { return __stl_debugger::_Check_same_or_null_owner(__i1,__i2); }
    423 
    424 template <class _Iterator>
    425 inline bool _STLP_CALL  __check_if_owner( const __owned_list* __owner,
    426                                           const _Iterator& __it)
    427 { return __stl_debugger::_Check_if_owner(__owner, (const __owned_link&)__it); }
    428 
    429 template <class _Iterator>
    430 inline bool _STLP_CALL __check_if_not_owner( const __owned_list* __owner,
    431                                              const _Iterator& __it)
    432 { return __stl_debugger::_Check_if_not_owner(__owner, (const __owned_link&)__it); }
    433 
    434 _STLP_MOVE_TO_STD_NAMESPACE
    435 
    436 _STLP_END_NAMESPACE
    437 
    438 #else
    439 #  define _STLP_VERBOSE_ASSERT(expr, diagnostic)
    440 #  define _STLP_DEBUG_CHECK(expr)
    441 #endif /* _STLP_DEBUG */
    442 
    443 #if defined (_STLP_ASSERTIONS)
    444 
    445 #  if !defined (_STLP_ASSERT_MSG_TRAILER)
    446 #    define _STLP_ASSERT_MSG_TRAILER
    447 #  endif
    448 
    449 // dwa 12/30/98 - if _STLP_DEBUG_MESSAGE is defined, the user can supply own definition.
    450 #  if !defined (_STLP_DEBUG_MESSAGE)
    451 #    define __stl_debug_message __stl_debugger::_Message
    452 #  else
    453 extern  void __stl_debug_message(const char * format_str, ...);
    454 #  endif
    455 
    456 // fbp: if _STLP_DEBUG_TERMINATE is defined, the user can supply own definition.
    457 #  if !defined (_STLP_DEBUG_TERMINATE)
    458 #    define __stl_debug_terminate __stl_debugger::_Terminate
    459 #  else
    460 extern  void __stl_debug_terminate();
    461 #  endif
    462 
    463 #endif
    464 
    465 #if defined (_STLP_ASSERTIONS) && !defined (_STLP_LINK_TIME_INSTANTIATION)
    466 #  include <stl/debug/_debug.c>
    467 #endif
    468 
    469 #endif /* DEBUG_H */
    470 
    471 // Local Variables:
    472 // mode:C++
    473 // End:
    474