X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f31a409829d5d410f38e64896470afcaff12635b..fcdd53359135f790b85728c4254b97095a56dad8:/src/msw/debughlp.cpp diff --git a/src/msw/debughlp.cpp b/src/msw/debughlp.cpp index 55a1006cf7..d2ddec0146 100644 --- a/src/msw/debughlp.cpp +++ b/src/msw/debughlp.cpp @@ -25,7 +25,15 @@ #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 @@ -137,7 +145,7 @@ const wxString& wxDbgHelpDLL::GetErrorMessage() void wxDbgHelpDLL::LogError(const wxChar *func) { ::OutputDebugString(wxString::Format(_T("dbghelp: %s() failed: %s\r\n"), - func, wxSysErrorMsg(::GetLastError()))); + func, wxSysErrorMsg(::GetLastError())).wx_str()); } // ---------------------------------------------------------------------------- @@ -286,7 +294,7 @@ wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level) wxString s; // avoid infinite recursion - if ( level > 100 ) + if ( level > MAX_DUMP_DEPTH ) { return s; } @@ -305,46 +313,53 @@ wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level) 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() ) @@ -366,20 +381,45 @@ wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level) 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; @@ -458,7 +498,16 @@ wxDbgHelpDLL::DereferenceSymbol(PSYMBOL_INFO pSym, void **ppData) // 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;