#include "wx/msw/debughlp.h"
-#if wxUSE_DBGHELP
+#if wxUSE_DBGHELP && wxUSE_DYNLIB_CLASS
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// to prevent recursion which could result from corrupted data we limit
+// ourselves to that many levels of embedded fields inside structs
+static const unsigned MAX_DUMP_DEPTH = 20;
// ----------------------------------------------------------------------------
// globals
void wxDbgHelpDLL::LogError(const wxChar *func)
{
::OutputDebugString(wxString::Format(_T("dbghelp: %s() failed: %s\r\n"),
- func, wxSysErrorMsg(::GetLastError())));
+ func, wxSysErrorMsg(::GetLastError())).wx_str());
}
// ----------------------------------------------------------------------------
wxString s;
// avoid infinite recursion
- if ( level > 100 )
+ if ( level > MAX_DUMP_DEPTH )
{
return s;
}
break;
case SYMBOL_TAG_DATA:
- wxDbgHelpDLL::DataKind kind;
- if ( !DoGetTypeInfo(pSym, TI_GET_DATAKIND, &kind) ||
- kind != DATA_MEMBER )
+ if ( !pVariable )
{
- // maybe it's a static member? we're not interested in them...
- break;
+ s = _T("NULL");
}
+ else // valid location
+ {
+ wxDbgHelpDLL::DataKind kind;
+ if ( !DoGetTypeInfo(pSym, TI_GET_DATAKIND, &kind) ||
+ kind != DATA_MEMBER )
+ {
+ // maybe it's a static member? we're not interested in them...
+ break;
+ }
- // get the offset of the child member, relative to its parent
- DWORD ofs = 0;
- if ( !DoGetTypeInfo(pSym, TI_GET_OFFSET, &ofs) )
- break;
+ // get the offset of the child member, relative to its parent
+ DWORD ofs = 0;
+ if ( !DoGetTypeInfo(pSym, TI_GET_OFFSET, &ofs) )
+ break;
- pVariable = (void *)((DWORD_PTR)pVariable + ofs);
+ pVariable = (void *)((DWORD_PTR)pVariable + ofs);
- // now pass to the type representing the type of this member
- SYMBOL_INFO sym = *pSym;
- if ( !DoGetTypeInfo(pSym, TI_GET_TYPEID, &sym.TypeIndex) )
- break;
+ // now pass to the type representing the type of this member
+ SYMBOL_INFO sym = *pSym;
+ if ( !DoGetTypeInfo(pSym, TI_GET_TYPEID, &sym.TypeIndex) )
+ break;
- ULONG64 size;
- DoGetTypeInfo(&sym, TI_GET_LENGTH, &size);
+ ULONG64 size;
+ DoGetTypeInfo(&sym, TI_GET_LENGTH, &size);
- switch ( DereferenceSymbol(&sym, &pVariable) )
- {
- case SYMBOL_TAG_BASE_TYPE:
- {
- BasicType bt = GetBasicType(&sym);
- if ( bt )
+ switch ( DereferenceSymbol(&sym, &pVariable) )
+ {
+ case SYMBOL_TAG_BASE_TYPE:
{
- s = DumpBaseType(bt, size, pVariable);
+ BasicType bt = GetBasicType(&sym);
+ if ( bt )
+ {
+ s = DumpBaseType(bt, size, pVariable);
+ }
}
- }
- break;
+ break;
- case SYMBOL_TAG_UDT:
- case SYMBOL_TAG_BASE_CLASS:
- s = DumpUDT(&sym, pVariable, level);
- break;
+ case SYMBOL_TAG_UDT:
+ case SYMBOL_TAG_BASE_CLASS:
+ s = DumpUDT(&sym, pVariable, level);
+ break;
+ }
}
if ( !s.empty() )
wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level)
{
wxString s;
+
+ // we have to limit the depth of UDT dumping as otherwise we get in
+ // infinite loops trying to dump linked lists... 10 levels seems quite
+ // reasonable, full information is in minidump file anyhow
+ if ( level > 10 )
+ return s;
+
s.reserve(512);
s = GetSymbolName(pSym);
-#if !wxUSE_STL
+#if !wxUSE_STD_STRING
// special handling for ubiquitous wxString: although the code below works
// for it as well, it shows the wxStringBase class and takes 4 lines
// instead of only one as this branch
if ( s == _T("wxString") )
{
wxString *ps = (wxString *)pVariable;
- s << _T("(\"") << *ps << _T(")\"");
+
+ // we can't just dump wxString directly as it could be corrupted or
+ // invalid and it could also be locked for writing (i.e. if we're
+ // between GetWriteBuf() and UngetWriteBuf() calls) and assert when we
+ // try to access it contents using public methods, so instead use our
+ // knowledge of its internals
+ const wxChar *p = NULL;
+ if ( !::IsBadReadPtr(ps, sizeof(wxString)) )
+ {
+ p = ps->data();
+ wxStringData *data = (wxStringData *)p - 1;
+ if ( ::IsBadReadPtr(data, sizeof(wxStringData)) ||
+ ::IsBadReadPtr(p, sizeof(wxChar *)*data->nAllocLength) )
+ {
+ p = NULL; // don't touch this pointer with 10 feet pole
+ }
+ }
+
+ s << _T("(\"") << (p ? p : _T("???")) << _T(")\"");
}
else // any other UDT
-#endif // !wxUSE_STL
+#endif // !wxUSE_STD_STRING
{
// Determine how many children this type has.
DWORD dwChildrenCount = 0;
// remove one level of indirection except for the char strings: we want
// to dump "char *" and not a single "char" for them
if ( ppData && *ppData && GetBasicType(pSym) != BASICTYPE_CHAR )
- *ppData = (void *)*((DWORD_PTR *)*ppData);
+ {
+ DWORD_PTR *pData = (DWORD_PTR *)*ppData;
+
+ if ( ::IsBadReadPtr(pData, sizeof(DWORD_PTR *)) )
+ {
+ break;
+ }
+
+ *ppData = (void *)*pData;
+ }
}
return tag;
// debugging helpers
// ----------------------------------------------------------------------------
-#ifndef NDEBUG
+// this code is very useful when debugging debughlp.dll-related code but
+// probably not worth having compiled in normally, please do not remove it!
+#if 0 // ndef NDEBUG
static wxString TagString(wxDbgHelpDLL::SymbolTag tag)
{
}
OutputDebugString(wxString::Format(_T("tag=%s%s"),
- nested ? _T("nested ") : _T(""),
+ nested ? _T("nested ") : wxEmptyString,
TagString(tag).c_str()));
if ( tag == wxDbgHelpDLL::SYMBOL_TAG_UDT )
{
OutputDebugString(wxString::Format(_T(", next ti=0x%x"), ti));
}
- OutputDebugString("\r\n");
+ OutputDebugString(_T("\r\n"));
}
#endif // NDEBUG