fix debug_stl for vc8; refactor/simplified implementation
This was SVN commit r5396.
This commit is contained in:
parent
677fa0518f
commit
0841404218
@ -155,275 +155,227 @@ char* debug_stl_simplify_name(char* name)
|
||||
// class for each combination, but that is clearly infeasible.
|
||||
//
|
||||
// containers might still be uninitialized when we call get_container_info on
|
||||
// them. we need to check if they are valid and only then use their contents.
|
||||
// them. we need to check if they are IsValid and only then use their contents.
|
||||
// to that end, we derive a validator class from each container,
|
||||
// cast the container's address to it, and call its valid() method.
|
||||
// cast the container's address to it, and call its IsValid() method.
|
||||
//
|
||||
// checks performed include: is size() realistic; does begin() come before
|
||||
// end(), etc. we need to leverage all invariants because the values are
|
||||
// random in release mode.
|
||||
//
|
||||
// rationale:
|
||||
// - we need a complete class for each container type because the
|
||||
// valid() function sometimes needs access to protected members of
|
||||
// the containers. since we can't grant access via friend without the
|
||||
// cooperation of the system headers, it needs to be in a derived class.
|
||||
// - since we cast our validator on top of the actual container,
|
||||
// it must not contain virtual functions (the vptr would shift addresses;
|
||||
// we can't really correct for this because it's totally non-portable).
|
||||
// - we don't bother with making this a template because there are enough
|
||||
// variations that we'd have to specialize everything anyway.
|
||||
// we sometimes need to access protected members of the STL containers.
|
||||
// granting access via friend is not possible since the system headers
|
||||
// must not be changed. that leaves us with two alternatives:
|
||||
// 1) write a 'shadow' class that has the same memory layout. this would
|
||||
// free us from the ugly Dinkumware naming conventions, but requires
|
||||
// more maintenance when the STL implementation changes.
|
||||
// 2) derive from the container. while not entirely bulletproof due to the
|
||||
// lack of virtual dtors, this is safe in practice because pointers are
|
||||
// neither returned to users nor freed. the only requirement is that
|
||||
// classes must not include virtual functions, because a vptr would
|
||||
// change the memory layout in unknown ways.
|
||||
//
|
||||
// it is rather difficult to abstract away implementation details of various
|
||||
// STL versions. we currently only really support Dinkumware due to
|
||||
// significant differences in the implementations of set, map and string.
|
||||
|
||||
// basic sanity checks shared by all containers.
|
||||
static bool container_valid(const void* front, size_t el_count)
|
||||
{
|
||||
// empty, must not be reported as invalid
|
||||
if(!el_count)
|
||||
return true;
|
||||
|
||||
// # elements is unbelievably high; assume it's invalid.
|
||||
if(el_count > 0x1000000)
|
||||
return false;
|
||||
|
||||
if(debug_is_pointer_bogus(front))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// standard containers
|
||||
|
||||
|
||||
|
||||
// vector iterators advance by sizeof(value_type) bytes; since we assume the
|
||||
// int specialization, we have to do this ourselves.
|
||||
|
||||
// deque iterator operator* depends on el_size
|
||||
|
||||
// map iterator operator++ depends on el_size
|
||||
|
||||
/*
|
||||
template<class T> class GenericContainer : public T
|
||||
// base class (slightly simplifies code by providing default implementations
|
||||
// that can be used for most containers).
|
||||
// Container is the complete type of the STL container (we can't pass this
|
||||
// as a template because Dinkumware _Tree requires different parameters)
|
||||
template<class Container>
|
||||
struct ContainerBase : public Container
|
||||
{
|
||||
public:
|
||||
bool valid(size_t el_size) const
|
||||
bool IsValid(size_t UNUSED(el_size)) const
|
||||
{
|
||||
if(!container_valid(&front(), el_count(el_size)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
size_t NumElements(size_t UNUSED(el_size)) const
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter : public T::const_iterator
|
||||
static const u8* DereferenceAndAdvance(typename Container::iterator& it, size_t UNUSED(el_size))
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t el_size)
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
++(*this);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// standard containers
|
||||
//
|
||||
|
||||
// it is rather difficult to abstract away implementation details of various
|
||||
// STL versions. we currently only support Dinkumware (that shipped with VC7)
|
||||
// chiefly due to set/map- (i.e. tree) and string-specific code.
|
||||
#if STL_DINKUMWARE
|
||||
|
||||
class Any_deque : public std::deque<int>
|
||||
{
|
||||
#if STL_DINKUMWARE
|
||||
// being declared as friend isn't enough;
|
||||
// our iterator still doesn't get access to std::deque.
|
||||
const u8* get_item(size_t i, size_t el_size) const
|
||||
{
|
||||
const u8** map = (const u8**)_Map;
|
||||
const size_t el_per_bucket = std::max(16u / el_size, 1u);
|
||||
const size_t bucket_idx = i / el_per_bucket;
|
||||
const size_t idx_in_bucket = i - bucket_idx * el_per_bucket;
|
||||
const u8* bucket = map[bucket_idx];
|
||||
const u8* p = bucket + idx_in_bucket*el_size;
|
||||
const u8* p = (const u8*)&*it;
|
||||
++it;
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
public:
|
||||
bool valid(size_t el_size) const
|
||||
{
|
||||
|
||||
struct Any_deque : public ContainerBase<std::deque<int> >
|
||||
{
|
||||
#if STL_DINKUMWARE
|
||||
if(!container_valid(_Map, _Mysize))
|
||||
return false;
|
||||
const size_t el_per_bucket = std::max(16u / el_size, 1u); // see _DEQUESIZ
|
||||
|
||||
bool IsValid(size_t el_size) const
|
||||
{
|
||||
const size_t el_per_bucket = ElementsPerBucket(el_size);
|
||||
// initial element is beyond end of first bucket
|
||||
if(_Myoff >= el_per_bucket)
|
||||
return false;
|
||||
// more elements reported than fit in all buckets
|
||||
if(_Mysize > _Mapsize * el_per_bucket)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
static const u8* DereferenceAndAdvance(iterator& stl_it, size_t el_size)
|
||||
{
|
||||
struct Iterator : public iterator
|
||||
{
|
||||
Any_deque& Container() const
|
||||
{
|
||||
return *(Any_deque*)_Mycont;
|
||||
}
|
||||
|
||||
size_t CurrentIndex() const
|
||||
{
|
||||
return _Myoff;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator& it = *(Iterator*)&stl_it;
|
||||
Any_deque& container = it.Container();
|
||||
const size_t currentIndex = it.CurrentIndex();
|
||||
const u8* p = container.GetNthElement(currentIndex, el_size);
|
||||
++it;
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t ElementsPerBucket(size_t el_size)
|
||||
{
|
||||
return std::max(16u / el_size, 1u); // see _DEQUESIZ
|
||||
}
|
||||
|
||||
const u8* GetNthElement(size_t i, size_t el_size) const
|
||||
{
|
||||
const size_t el_per_bucket = ElementsPerBucket(el_size);
|
||||
const size_t bucket_idx = i / el_per_bucket;
|
||||
debug_assert(bucket_idx < _Mapsize);
|
||||
const size_t idx_in_bucket = i - bucket_idx * el_per_bucket;
|
||||
debug_assert(idx_in_bucket < el_per_bucket);
|
||||
const u8** map = (const u8**)_Map;
|
||||
const u8* bucket = map[bucket_idx];
|
||||
const u8* p = bucket + idx_in_bucket*el_size;
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
struct Any_list : public ContainerBase<std::list<int> >
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
#if STL_DINKUMWARE
|
||||
|
||||
template<class _Traits>
|
||||
struct Any_tree : public std::_Tree<_Traits>
|
||||
{
|
||||
Any_tree() // (required because default ctor cannot be generated)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsValid(size_t UNUSED(el_size)) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t NumElements(size_t UNUSED(el_size)) const
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter;
|
||||
friend class iter;
|
||||
class iter : public const_iterator
|
||||
static const u8* DereferenceAndAdvance(iterator& stl_it, size_t el_size)
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t el_size)
|
||||
struct Iterator : public const_iterator
|
||||
{
|
||||
const u8* p;
|
||||
#if STL_DINKUMWARE
|
||||
Any_deque* d = (Any_deque*)_Mycont;
|
||||
p = d->get_item(_Myoff, el_size);
|
||||
#else
|
||||
p = (const u8*)&operator*();
|
||||
#endif
|
||||
++(*this);
|
||||
_Nodeptr Node() const
|
||||
{
|
||||
return _Ptr;
|
||||
}
|
||||
|
||||
void SetNode(_Nodeptr node)
|
||||
{
|
||||
_Ptr = node;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator& it = *(Iterator*)&stl_it;
|
||||
_Nodeptr node = it.Node();
|
||||
const u8* p = (const u8*)&*it;
|
||||
|
||||
// end() shouldn't be incremented, don't move
|
||||
if(_Isnil(node, el_size))
|
||||
return p;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
class Any_list : public std::list<int>
|
||||
{
|
||||
public:
|
||||
bool valid(size_t UNUSED(el_size)) const
|
||||
{
|
||||
#if STL_DINKUMWARE
|
||||
if(!container_valid(_Myhead, _Mysize))
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter : public const_iterator
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t UNUSED(el_size))
|
||||
// return smallest (leftmost) node of right subtree
|
||||
_Nodeptr _Pnode = _Right(node);
|
||||
if(!_Isnil(_Pnode, el_size))
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
++(*this);
|
||||
return p;
|
||||
while(!_Isnil(_Left(_Pnode), el_size))
|
||||
_Pnode = _Left(_Pnode);
|
||||
}
|
||||
// climb looking for right subtree
|
||||
else
|
||||
{
|
||||
while (!_Isnil(_Pnode = _Parent(node), el_size) && node == _Right(_Pnode))
|
||||
node = _Pnode; // ==> parent while right subtree
|
||||
}
|
||||
it.SetNode(_Pnode);
|
||||
return p;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template<class _Traits> class Any_tree : public std::_Tree<_Traits>
|
||||
{
|
||||
private:
|
||||
// return reference to the given node's nil flag.
|
||||
// reimplemented because this member is stored after _Myval, so it's
|
||||
// dependent on el_size.
|
||||
static _Charref _Isnil(_Nodeptr _Pnode, size_t el_size)
|
||||
{
|
||||
const u8* p = (const u8*)&_Pnode->_Isnil; // ok for int specialization
|
||||
p += el_size - sizeof(value_type);
|
||||
// account for el_size difference
|
||||
const u8* p = (const u8*)&_Pnode->_Isnil; // correct for int specialization
|
||||
p += el_size - sizeof(value_type); // adjust for difference in el_size
|
||||
assert(*p <= 1); // bool value
|
||||
return (_Charref)*p;
|
||||
}
|
||||
|
||||
public:
|
||||
Any_tree() {}
|
||||
|
||||
bool valid(size_t UNUSED(el_size)) const
|
||||
{
|
||||
if(!container_valid(_Myhead, _Mysize))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter;
|
||||
friend class iter;
|
||||
class iter : public const_iterator
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t el_size)
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
|
||||
// end() shouldn't be incremented, don't move
|
||||
if(_Isnil(_Ptr, el_size))
|
||||
return p;
|
||||
|
||||
// return smallest (leftmost) node of right subtree
|
||||
_Nodeptr _Pnode = _Right(_Ptr);
|
||||
if(!_Isnil(_Pnode, el_size))
|
||||
{
|
||||
while(!_Isnil(_Left(_Pnode), el_size))
|
||||
_Pnode = _Left(_Pnode);
|
||||
}
|
||||
// climb looking for right subtree
|
||||
else
|
||||
{
|
||||
while (!_Isnil(_Pnode = _Parent(_Ptr), el_size)
|
||||
&& _Ptr == _Right(_Pnode))
|
||||
_Ptr = _Pnode; // ==> parent while right subtree
|
||||
}
|
||||
_Ptr = _Pnode;
|
||||
|
||||
return p;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
class Any_map : public Any_tree<std::_Tmap_traits<int, int, std::less<int>, std::allocator<std::pair<const int, int> >, false> >
|
||||
struct Any_map : public Any_tree<std::_Tmap_traits<int, int, std::less<int>, std::allocator<std::pair<const int, int> >, false> >
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
class Any_multimap : public Any_map
|
||||
struct Any_multimap : public Any_map
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
class Any_set: public Any_tree<std::_Tset_traits<int, std::less<int>, std::allocator<int>, false> >
|
||||
struct Any_set: public Any_tree<std::_Tset_traits<int, std::less<int>, std::allocator<int>, false> >
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
class Any_multiset: public Any_set
|
||||
struct Any_multiset: public Any_set
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
class Any_vector: public std::vector<int>
|
||||
{
|
||||
public:
|
||||
bool valid(size_t UNUSED(el_size)) const
|
||||
{
|
||||
#if STL_DINKUMWARE
|
||||
if(!container_valid(_Myfirst, _Mylast-_Myfirst))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
|
||||
struct Any_vector: public ContainerBase<std::vector<int> >
|
||||
{
|
||||
bool IsValid(size_t UNUSED(el_size)) const
|
||||
{
|
||||
// more elements reported than reserved
|
||||
if(size() > capacity())
|
||||
return false;
|
||||
@ -433,68 +385,55 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t el_size) const
|
||||
#if STL_DINKUMWARE
|
||||
|
||||
size_t NumElements(size_t el_size) const
|
||||
{
|
||||
// vectors store front and back pointers and calculate
|
||||
// vectors store front and back pointers and calculate their
|
||||
// element count as the difference between them. since we are
|
||||
// derived from the int specialization, the pointer arithmetic is
|
||||
// off. we fix it by taking el_size into account.
|
||||
return size() * 4 / el_size;
|
||||
// derived from a template specialization, the pointer arithmetic
|
||||
// is incorrect. we fix it by taking el_size into account.
|
||||
return ((u8*)_Mylast - (u8*)_Myfirst) * el_size;
|
||||
}
|
||||
|
||||
class iter : public const_iterator
|
||||
static const u8* DereferenceAndAdvance(iterator& stl_it, size_t el_size)
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t el_size)
|
||||
struct Iterator : public const_iterator
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
_Myptr = (_Tptr)((u8*)_Myptr + el_size);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
void Advance(size_t numBytes)
|
||||
{
|
||||
(u8*&)_Myptr += numBytes;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator& it = *(Iterator*)&stl_it;
|
||||
const u8* p = (const u8*)&*it;
|
||||
it.Advance(el_size);
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
class Any_basic_string : public std::string
|
||||
{
|
||||
const void* ptr(size_t el_size) const
|
||||
{
|
||||
return _Myres <= (16/el_size)-1? _Bx._Buf : _Bx._Ptr;
|
||||
}
|
||||
|
||||
public:
|
||||
bool valid(size_t el_size) const
|
||||
{
|
||||
if(!container_valid(ptr(el_size), _Mysize))
|
||||
return false;
|
||||
#if STL_DINKUMWARE
|
||||
|
||||
struct Any_basic_string : public ContainerBase<std::string>
|
||||
{
|
||||
bool IsValid(size_t el_size) const
|
||||
{
|
||||
// less than the small buffer reserved - impossible
|
||||
if(_Myres < (16/el_size)-1)
|
||||
return false;
|
||||
// more elements reported than reserved
|
||||
if(_Mysize > _Myres)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter : public const_iterator
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t UNUSED(el_size))
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
++(*this);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// standard container adapters
|
||||
@ -502,14 +441,14 @@ public:
|
||||
|
||||
// debug_stl_get_container_info makes sure this was actually instantiated with
|
||||
// container = deque as we assume.
|
||||
class Any_queue : public Any_deque
|
||||
struct Any_queue : public Any_deque
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
// debug_stl_get_container_info makes sure this was actually instantiated with
|
||||
// container = deque as we assume.
|
||||
class Any_stack : public Any_deque
|
||||
struct Any_stack : public Any_deque
|
||||
{
|
||||
};
|
||||
|
||||
@ -520,71 +459,44 @@ class Any_stack : public Any_deque
|
||||
|
||||
#if HAVE_STL_HASH
|
||||
|
||||
|
||||
class Any_hash_map: public STL_HASH_MAP<int,int>
|
||||
struct Any_hash_map: public ContainerBase<STL_HASH_MAP<int,int> >
|
||||
{
|
||||
public:
|
||||
bool valid(size_t el_size) const
|
||||
#if STL_DINKUMWARE
|
||||
|
||||
bool IsValid(size_t el_size) const
|
||||
{
|
||||
Any_list* list = (Any_list*)&_List;
|
||||
if(!list->valid(el_size))
|
||||
if(!list->IsValid(el_size))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter : public const_iterator
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t UNUSED(el_size))
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
++(*this);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
class Any_hash_multimap : public Any_hash_map
|
||||
struct Any_hash_multimap : public Any_hash_map
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
class Any_hash_set: public STL_HASH_SET<int>
|
||||
struct Any_hash_set: public ContainerBase<STL_HASH_SET<int> >
|
||||
{
|
||||
public:
|
||||
bool valid(size_t el_size) const
|
||||
#if STL_DINKUMWARE
|
||||
|
||||
bool IsValid(size_t el_size) const
|
||||
{
|
||||
Any_list* list = (Any_list*)&_List;
|
||||
if(!list->valid(el_size))
|
||||
if(!list->IsValid(el_size))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter : public const_iterator
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t UNUSED(el_size))
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
++(*this);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
class Any_hash_multiset : public Any_hash_set
|
||||
struct Any_hash_multiset : public Any_hash_set
|
||||
{
|
||||
};
|
||||
|
||||
@ -592,42 +504,74 @@ class Any_hash_multiset : public Any_hash_set
|
||||
|
||||
#if HAVE_STL_SLIST
|
||||
|
||||
|
||||
class Any_slist: public Any_list
|
||||
struct Any_slist: public Any_list
|
||||
{
|
||||
};
|
||||
|
||||
#endif // HAVE_STL_SLIST
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// generic iterator - returns next element. dereferences and increments the
|
||||
// specific container iterator stored in it_mem.
|
||||
template<class T> const u8* stl_iterator(void* it_mem, size_t el_size)
|
||||
{
|
||||
T::iter* pi = (T::iter*)it_mem;
|
||||
return pi->deref_and_advance(el_size);
|
||||
T::iterator& stl_it = *(T::iterator*)it_mem;
|
||||
return T::DereferenceAndAdvance(stl_it, el_size);
|
||||
}
|
||||
|
||||
|
||||
// check if the container is valid and return # elements and an iterator;
|
||||
// basic sanity checks that apply to all containers.
|
||||
template<class T>
|
||||
static bool IsContainerValid(const T& t, size_t el_count)
|
||||
{
|
||||
// note: don't test empty() because vector's implementation of it
|
||||
// depends on el_size.
|
||||
|
||||
// size must be reasonable
|
||||
if(el_count > 0x1000000)
|
||||
return false;
|
||||
|
||||
if(el_count != 0)
|
||||
{
|
||||
// valid pointer
|
||||
const u8* front = (const u8*)&*t.begin(); // (note: map doesn't have front)
|
||||
if(debug_is_pointer_bogus(front))
|
||||
return false;
|
||||
|
||||
// note: don't test back() because that depends on el_size and
|
||||
// requires container-specific code.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// check if the container is IsValid and return # elements and an iterator;
|
||||
// this is instantiated once for each type of container.
|
||||
// we don't do this in the Any_* ctors because we need to return bool valid and
|
||||
// we don't do this in the Any_* ctors because we need to return bool IsValid and
|
||||
// don't want to throw an exception (may confuse the debug code).
|
||||
template<class T> bool get_container_info(T* t, size_t size, size_t el_size,
|
||||
size_t* el_count, DebugIterator* el_iterator, void* it_mem)
|
||||
template<class T> bool get_container_info(const T& t, size_t size, size_t el_size,
|
||||
size_t& el_count, DebugStlIterator& el_iterator, void* it_mem)
|
||||
{
|
||||
debug_assert(sizeof(T) == size);
|
||||
debug_assert(sizeof(T::iterator) < DEBUG_STL_MAX_ITERATOR_SIZE);
|
||||
|
||||
el_count = t.NumElements(el_size);
|
||||
|
||||
// bail if the container is uninitialized/invalid.
|
||||
// check this before calling el_count etc. because they may crash.
|
||||
if(!t->valid(el_size))
|
||||
if(!IsContainerValid(t, el_count))
|
||||
return false;
|
||||
|
||||
*el_count = t->el_count(el_size);
|
||||
*el_iterator = stl_iterator<T>;
|
||||
*(T::const_iterator*)it_mem = t->begin();
|
||||
el_iterator = stl_iterator<T>;
|
||||
|
||||
// construct a copy of begin() at it_mem. placement new is necessary
|
||||
// because VC8's secure copy ctor apparently otherwise complains about
|
||||
// invalid values in the (uninitialized) destination memory.
|
||||
#include "lib/nommgr.h"
|
||||
new(it_mem) T::const_iterator(t.begin());
|
||||
#include "lib/mmgr.h"
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -638,21 +582,14 @@ template<class T> bool get_container_info(T* t, size_t size, size_t el_size,
|
||||
// it_mem, which must hold DEBUG_STL_MAX_ITERATOR_SIZE bytes).
|
||||
// returns 0 on success or an StlContainerError.
|
||||
LibError debug_stl_get_container_info(const char* type_name, const u8* p, size_t size,
|
||||
size_t el_size, size_t* el_count, DebugIterator* el_iterator, void* it_mem)
|
||||
size_t el_size, size_t* el_count, DebugStlIterator* el_iterator, void* it_mem)
|
||||
{
|
||||
// HACK: The debug_stl code breaks VS2005's STL badly, causing crashes in
|
||||
// later pieces of code that try to manipulate the STL containers. Presumably
|
||||
// it needs to be altered/rewritten to work happily with the new STL debug iterators.
|
||||
#if MSC_VERSION >= 1400
|
||||
return ERR::FAIL;
|
||||
#endif
|
||||
|
||||
bool handled = false, valid = false;
|
||||
bool handled = false, IsValid = false;
|
||||
#define CONTAINER(name, type_name_pattern)\
|
||||
else if(match_wildcard(type_name, type_name_pattern))\
|
||||
{\
|
||||
handled = true;\
|
||||
valid = get_container_info<Any_##name>((Any_##name*)p, size, el_size, el_count, el_iterator, it_mem);\
|
||||
IsValid = get_container_info<Any_##name>(*(Any_##name*)p, size, el_size, *el_count, *el_iterator, it_mem);\
|
||||
}
|
||||
#define STD_CONTAINER(name) CONTAINER(name, "std::" #name "<*>")
|
||||
|
||||
@ -665,15 +602,15 @@ LibError debug_stl_get_container_info(const char* type_name, const u8* p, size_t
|
||||
|
||||
if(0) {} // kickoff
|
||||
// standard containers
|
||||
STD_CONTAINER(deque) // deref provided
|
||||
STD_CONTAINER(list) // ok
|
||||
STD_CONTAINER(map) // advance provided
|
||||
STD_CONTAINER(multimap) // advance provided
|
||||
STD_CONTAINER(set) // TODO use map impl?
|
||||
STD_CONTAINER(multiset) // TODO use map impl?
|
||||
STD_CONTAINER(vector) // special-cased
|
||||
STD_CONTAINER(basic_string) // ok
|
||||
// standard container adapter
|
||||
STD_CONTAINER(deque)
|
||||
STD_CONTAINER(list)
|
||||
STD_CONTAINER(map)
|
||||
STD_CONTAINER(multimap)
|
||||
STD_CONTAINER(set)
|
||||
STD_CONTAINER(multiset)
|
||||
STD_CONTAINER(vector)
|
||||
STD_CONTAINER(basic_string)
|
||||
// standard container adapters
|
||||
// (note: Any_queue etc. assumes the underlying container is a deque.
|
||||
// we make sure of that here and otherwise refuse to display it, because
|
||||
// doing so is lots of work for little gain.)
|
||||
@ -694,9 +631,7 @@ LibError debug_stl_get_container_info(const char* type_name, const u8* p, size_t
|
||||
// STL classes or if the debuggee's memory is corrupted.
|
||||
if(!handled)
|
||||
return ERR::STL_CNT_UNKNOWN; // NOWARN
|
||||
if(!valid)
|
||||
if(!IsValid)
|
||||
return ERR::STL_CNT_INVALID; // NOWARN
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -38,7 +38,7 @@ extern char* debug_stl_simplify_name(char* name);
|
||||
/**
|
||||
* abstraction of all STL iterators used by debug_stl.
|
||||
**/
|
||||
typedef const u8* (*DebugIterator)(void* internal, size_t el_size);
|
||||
typedef const u8* (*DebugStlIterator)(void* internal, size_t el_size);
|
||||
|
||||
/**
|
||||
* no STL iterator is larger than this; see below.
|
||||
@ -64,6 +64,6 @@ const size_t DEBUG_STL_MAX_ITERATOR_SIZE = 64;
|
||||
* @return LibError (ERR::STL_*)
|
||||
**/
|
||||
extern LibError debug_stl_get_container_info(const char* type_name, const u8* p, size_t size,
|
||||
size_t el_size, size_t* el_count, DebugIterator* el_iterator, void* it_mem);
|
||||
size_t el_size, size_t* el_count, DebugStlIterator* el_iterator, void* it_mem);
|
||||
|
||||
#endif // #ifndef INCLUDED_DEBUG_STL
|
||||
|
@ -806,7 +806,7 @@ static void seq_determine_formatting(size_t el_size, size_t el_count,
|
||||
}
|
||||
|
||||
|
||||
static LibError dump_sequence(DebugIterator el_iterator, void* internal,
|
||||
static LibError dump_sequence(DebugStlIterator el_iterator, void* internal,
|
||||
size_t el_count, DWORD el_type_id, size_t el_size, DumpState state)
|
||||
{
|
||||
const u8* el_p = 0; // avoid "uninitialized" warning
|
||||
@ -1452,7 +1452,7 @@ static LibError udt_dump_std(const wchar_t* wtype_name, const u8* p, size_t size
|
||||
goto not_valid_container;
|
||||
// .. get iterator and # elements
|
||||
size_t el_count;
|
||||
DebugIterator el_iterator;
|
||||
DebugStlIterator el_iterator;
|
||||
u8 it_mem[DEBUG_STL_MAX_ITERATOR_SIZE];
|
||||
err = debug_stl_get_container_info(ctype_name, p, size, el_size, &el_count, &el_iterator, it_mem);
|
||||
if(err != INFO::OK)
|
||||
|
Loading…
Reference in New Issue
Block a user