home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / memory.cpp < prev    next >
C/C++ Source or Header  |  2002-09-12  |  28KB  |  1,087 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        memory.cpp
  3. // Purpose:     Memory checking implementation
  4. // Author:      Arthur Seaton, Julian Smart
  5. // Modified by:
  6. // Created:     04/01/98
  7. // RCS-ID:      $Id: memory.cpp,v 1.51 2002/09/12 08:51:01 JS Exp $
  8. // Copyright:   (c) Julian Smart and Markus Holzem
  9. // Licence:     wxWindows license
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "memory.h"
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22.  
  23. #ifndef WX_PRECOMP
  24. #include "wx/defs.h"
  25. #endif
  26.  
  27. #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
  28.  
  29. #ifdef __GNUG__
  30. // #pragma implementation
  31. #endif
  32.  
  33. #ifndef WX_PRECOMP
  34. #include "wx/utils.h"
  35. #include "wx/app.h"
  36. #endif
  37.  
  38. #if wxUSE_THREADS
  39. #include "wx/thread.h"
  40. #endif
  41.  
  42. #include "wx/log.h"
  43. #include <stdlib.h>
  44.  
  45. #include "wx/ioswrap.h"
  46.  
  47. #if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\
  48.      && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
  49. #include <memory.h>
  50. #endif
  51.  
  52. #include <stdarg.h>
  53. #include <string.h>
  54.  
  55. #ifdef __WXMSW__
  56. #include <windows.h>
  57.  
  58. #ifdef GetClassInfo
  59. #undef GetClassInfo
  60. #endif
  61.  
  62. #ifdef GetClassName
  63. #undef GetClassName
  64. #endif
  65.  
  66. #endif
  67.  
  68. #include "wx/memory.h"
  69.  
  70. #if wxUSE_THREADS && defined(__WXDEBUG__) && !defined(__WXMAC__)
  71. #define USE_THREADSAFE_MEMORY_ALLOCATION 1
  72. #else
  73. #define USE_THREADSAFE_MEMORY_ALLOCATION 0
  74. #endif
  75.  
  76.  
  77. #ifdef new
  78. #undef new
  79. #endif
  80.  
  81. // wxDebugContext wxTheDebugContext;
  82. /*
  83.   Redefine new and delete so that we can pick up situations where:
  84.         - we overwrite or underwrite areas of malloc'd memory.
  85.         - we use uninitialise variables
  86.   Only do this in debug mode.
  87.  
  88.   We change new to get enough memory to allocate a struct, followed
  89.   by the caller's requested memory, followed by a tag. The struct
  90.   is used to create a doubly linked list of these areas and also
  91.   contains another tag. The tags are used to determine when the area
  92.   has been over/under written.
  93. */
  94.  
  95.  
  96. /*
  97.   Values which are used to set the markers which will be tested for
  98.   under/over write. There are 3 of these, one in the struct, one
  99.   immediately after the struct but before the caller requested memory and
  100.   one immediately after the requested memory.
  101. */
  102. #define MemStartCheck  0x23A8
  103. #define MemMidCheck  0xA328
  104. #define MemEndCheck 0x8A32
  105. #define MemFillChar 0xAF
  106. #define MemStructId  0x666D
  107.  
  108. /*
  109.   External interface for the wxMemStruct class. Others are
  110.   defined inline within the class def. Here we only need to be able
  111.   to add and delete nodes from the list and handle errors in some way.
  112. */
  113.  
  114. /*
  115.   Used for internal "this shouldn't happen" type of errors.
  116. */
  117. void wxMemStruct::ErrorMsg (const char * mesg)
  118. {
  119.   wxLogMessage(wxT("wxWindows memory checking error: %s"), mesg);
  120.   PrintNode ();
  121. }
  122.  
  123. /*
  124.   Used when we find an overwrite or an underwrite error.
  125. */
  126. void wxMemStruct::ErrorMsg ()
  127. {
  128.   wxLogMessage(wxT("wxWindows over/underwrite memory error:"));
  129.   PrintNode ();
  130. }
  131.  
  132.  
  133. /*
  134.   We want to find out if pointers have been overwritten as soon as is
  135.   possible, so test everything before we dereference it. Of course it's still
  136.   quite possible that, if things have been overwritten, this function will
  137.   fall over, but the only way of dealing with that would cost too much in terms
  138.   of time.
  139. */
  140. int wxMemStruct::AssertList ()
  141. {
  142.     if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () ||
  143.         wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) {
  144.         ErrorMsg ("Head or tail pointers trashed");
  145.         return 0;
  146.     }
  147.     return 1;
  148. }
  149.  
  150.  
  151. /*
  152.   Check that the thing we're pointing to has the correct id for a wxMemStruct
  153.   object and also that it's previous and next pointers are pointing at objects
  154.   which have valid ids.
  155.   This is definitely not perfect since we could fall over just trying to access
  156.   any of the slots which we use here, but I think it's about the best that I
  157.   can do without doing something like taking all new wxMemStruct pointers and
  158.   comparing them against all known pointer within the list and then only
  159.   doing this sort of check _after_ you've found the pointer in the list. That
  160.   would be safer, but also much more time consuming.
  161. */
  162. int wxMemStruct::AssertIt ()
  163. {
  164.     return (m_id == MemStructId &&
  165.             (m_prev == 0 || m_prev->m_id == MemStructId) &&
  166.             (m_next == 0 || m_next->m_id == MemStructId));
  167. }
  168.  
  169.  
  170. /*
  171.   Additions are always at the tail of the list.
  172.   Returns 0 on error, non-zero on success.
  173. */
  174. int wxMemStruct::Append ()
  175. {
  176.     if (! AssertList ())
  177.         return 0;
  178.  
  179.     if (wxDebugContext::GetHead () == 0) {
  180.         if (wxDebugContext::GetTail () != 0) {
  181.             ErrorMsg ("Null list should have a null tail pointer");
  182.             return 0;
  183.         }
  184.         (void) wxDebugContext::SetHead (this);
  185.         (void) wxDebugContext::SetTail (this);
  186.     } else {
  187.         wxDebugContext::GetTail ()->m_next = this;
  188.         this->m_prev = wxDebugContext::GetTail ();
  189.         (void) wxDebugContext::SetTail (this);
  190.     }
  191.     return 1;
  192. }
  193.  
  194.  
  195. /*
  196.   Don't actually free up anything here as the space which is used
  197.   by the node will be free'd up when the whole block is free'd.
  198.   Returns 0 on error, non-zero on success.
  199. */
  200. int wxMemStruct::Unlink ()
  201. {
  202.     if (! AssertList ())
  203.         return 0;
  204.  
  205.     if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
  206.         ErrorMsg ("Trying to remove node from empty list");
  207.         return 0;
  208.     }
  209.  
  210.     // Handle the part of the list before this node.
  211.     if (m_prev == 0) {
  212.         if (this != wxDebugContext::GetHead ()) {
  213.             ErrorMsg ("No previous node for non-head node");
  214.             return 0;
  215.         }
  216.         (void) wxDebugContext::SetHead (m_next);
  217.     } else {
  218.         if (! m_prev->AssertIt ()) {
  219.             ErrorMsg ("Trashed previous pointer");
  220.             return 0;
  221.         }
  222.  
  223.         if (m_prev->m_next != this) {
  224.             ErrorMsg ("List is inconsistent");
  225.             return 0;
  226.         }
  227.         m_prev->m_next = m_next;
  228.     }
  229.  
  230.     // Handle the part of the list after this node.
  231.     if (m_next == 0) {
  232.         if (this != wxDebugContext::GetTail ()) {
  233.             ErrorMsg ("No next node for non-tail node");
  234.             return 0;
  235.         }
  236.         (void) wxDebugContext::SetTail (m_prev);
  237.     } else {
  238.         if (! m_next->AssertIt ()) {
  239.             ErrorMsg ("Trashed next pointer");
  240.             return 0;
  241.         }
  242.  
  243.         if (m_next->m_prev != this) {
  244.             ErrorMsg ("List is inconsistent");
  245.             return 0;
  246.         }
  247.         m_next->m_prev = m_prev;
  248.     }
  249.  
  250.     return 1;
  251. }
  252.  
  253.  
  254.  
  255. /*
  256.   Checks a node and block of memory to see that the markers are still
  257.   intact.
  258. */
  259. int wxMemStruct::CheckBlock ()
  260. {
  261.     int nFailures = 0;
  262.  
  263.     if (m_firstMarker != MemStartCheck) {
  264.         nFailures++;
  265.         ErrorMsg ();
  266.     }
  267.  
  268.     char * pointer = wxDebugContext::MidMarkerPos ((char *) this);
  269.     if (* (wxMarkerType *) pointer != MemMidCheck) {
  270.         nFailures++;
  271.         ErrorMsg ();
  272.     }
  273.  
  274.     pointer = wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
  275.     if (* (wxMarkerType *) pointer != MemEndCheck) {
  276.         nFailures++;
  277.         ErrorMsg ();
  278.     }
  279.  
  280.     return nFailures;
  281. }
  282.  
  283.  
  284. /*
  285.   Check the list of nodes to see if they are all ok.
  286. */
  287. int wxMemStruct::CheckAllPrevious ()
  288. {
  289.     int nFailures = 0;
  290.  
  291.     for (wxMemStruct * st = this->m_prev; st != 0; st = st->m_prev) {
  292.         if (st->AssertIt ())
  293.             nFailures += st->CheckBlock ();
  294.         else
  295.             return -1;
  296.     }
  297.  
  298.     return nFailures;
  299. }
  300.  
  301.  
  302. /*
  303.   When we delete a node we set the id slot to a specific value and then test
  304.   against this to see if a nodes have been deleted previously. I don't
  305.   just set the entire memory to the fillChar because then I'd be overwriting
  306.   useful stuff like the vtbl which may be needed to output the error message
  307.   including the file name and line numbers. Without this info the whole point
  308.   of this class is lost!
  309. */
  310. void wxMemStruct::SetDeleted ()
  311. {
  312.     m_id = MemFillChar;
  313. }
  314.  
  315. int wxMemStruct::IsDeleted ()
  316. {
  317.     return (m_id == MemFillChar);
  318. }
  319.  
  320.  
  321. /*
  322.   Print out a single node. There are many far better ways of doing this
  323.   but this will suffice for now.
  324. */
  325. void wxMemStruct::PrintNode ()
  326. {
  327.   if (m_isObject)
  328.   {
  329.     wxObject *obj = (wxObject *)m_actualData;
  330.     wxClassInfo *info = obj->GetClassInfo();
  331.  
  332.     // Let's put this in standard form so IDEs can load the file at the appropriate
  333.     // line
  334.     wxString msg(wxT(""));
  335.  
  336.     if (m_fileName)
  337.       msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
  338.  
  339.     if (info && info->GetClassName())
  340.       msg += info->GetClassName();
  341.     else
  342.       msg += wxT("object");
  343.  
  344.     wxString msg2;
  345.     msg2.Printf(wxT(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize());
  346.     msg += msg2;
  347.  
  348.     wxLogMessage(msg);
  349.   }
  350.   else
  351.   {
  352.     wxString msg("");
  353.  
  354.     if (m_fileName)
  355.       msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
  356.     msg += wxT("non-object data");
  357.     wxString msg2;
  358.     msg2.Printf(wxT(" at $%lX, size %d\n"), (long)GetActualData(), (int)RequestSize());
  359.     msg += msg2;
  360.  
  361.     wxLogMessage(msg);
  362.   }
  363. }
  364.  
  365. void wxMemStruct::Dump ()
  366. {
  367.   if (!ValidateNode()) return;
  368.  
  369.   if (m_isObject)
  370.   {
  371.     wxObject *obj = (wxObject *)m_actualData;
  372.  
  373.     wxString msg(wxT(""));
  374.     if (m_fileName)
  375.       msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
  376.  
  377.  
  378.     /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
  379.      * Instead, do what wxObject::Dump does.
  380.      * What should we do long-term, eliminate Dumping? Or specify
  381.      * that MyClass::Dump should use wxLogDebug? Ugh.
  382.     obj->Dump(wxDebugContext::GetStream());
  383.      */
  384.  
  385.     if (obj->GetClassInfo() && obj->GetClassInfo()->GetClassName())
  386.       msg += obj->GetClassInfo()->GetClassName();
  387.     else
  388.       msg += wxT("unknown object class");
  389.  
  390.     wxString msg2("");
  391.     msg2.Printf(wxT(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize());
  392.     msg += msg2;
  393.  
  394.     wxLogMessage(msg);
  395.   }
  396.   else
  397.   {
  398.     wxString msg(wxT(""));
  399.     if (m_fileName)
  400.       msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
  401.  
  402.     wxString msg2("");
  403.     msg2.Printf(wxT("non-object data at $%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
  404.     msg += msg2;
  405.     wxLogMessage(msg);
  406.   }
  407. }
  408.  
  409.  
  410. /*
  411.   Validate a node. Check to see that the node is "clean" in the sense
  412.   that nothing has over/underwritten it etc.
  413. */
  414. int wxMemStruct::ValidateNode ()
  415. {
  416.     char * startPointer = (char *) this;
  417.     if (!AssertIt ()) {
  418.         if (IsDeleted ())
  419.             ErrorMsg ("Object already deleted");
  420.         else {
  421.             // Can't use the error routines as we have no recognisable object.
  422. #ifndef __WXGTK__
  423.              wxLogMessage(wxT("Can't verify memory struct - all bets are off!"));
  424. #endif
  425.         }
  426.         return 0;
  427.     }
  428.  
  429. /*
  430.     int i;
  431.     for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
  432.       cout << startPointer [i];
  433.     cout << endl;
  434. */
  435.     if (Marker () != MemStartCheck)
  436.       ErrorMsg ();
  437.     if (* (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) != MemMidCheck)
  438.       ErrorMsg ();
  439.     if (* (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer,
  440.                                               RequestSize ()) !=
  441.         MemEndCheck)
  442.       ErrorMsg ();
  443.  
  444.     // Back to before the extra buffer and check that
  445.     // we can still read what we originally wrote.
  446.     if (Marker () != MemStartCheck ||
  447.         * (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer)
  448.                          != MemMidCheck ||
  449.         * (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer,
  450.                                               RequestSize ()) != MemEndCheck)
  451.     {
  452.         ErrorMsg ();
  453.         return 0;
  454.     }
  455.  
  456.     return 1;
  457. }
  458.  
  459. /*
  460.   The wxDebugContext class.
  461. */
  462.  
  463. wxMemStruct *wxDebugContext::m_head = NULL;
  464. wxMemStruct *wxDebugContext::m_tail = NULL;
  465.  
  466. bool wxDebugContext::m_checkPrevious = FALSE;
  467. int wxDebugContext::debugLevel = 1;
  468. bool wxDebugContext::debugOn = TRUE;
  469. wxMemStruct *wxDebugContext::checkPoint = NULL;
  470.  
  471. // For faster alignment calculation
  472. static wxMarkerType markerCalc[2];
  473. int wxDebugContext::m_balign = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]);
  474. int wxDebugContext::m_balignmask = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]) - 1;
  475.  
  476. wxDebugContext::wxDebugContext(void)
  477. {
  478. }
  479.  
  480. wxDebugContext::~wxDebugContext(void)
  481. {
  482. }
  483.  
  484. /*
  485.   Work out the positions of the markers by creating an array of 2 markers
  486.   and comparing the addresses of the 2 elements. Use this number as the
  487.   alignment for markers.
  488. */
  489. size_t wxDebugContext::CalcAlignment ()
  490. {
  491.     wxMarkerType ar[2];
  492.     return (char *) &ar[1] - (char *) &ar[0];
  493. }
  494.  
  495.  
  496. char * wxDebugContext::StructPos (const char * buf)
  497. {
  498.     return (char *) buf;
  499. }
  500.  
  501. char * wxDebugContext::MidMarkerPos (const char * buf)
  502. {
  503.     return StructPos (buf) + PaddedSize (sizeof (wxMemStruct));
  504. }
  505.  
  506. char * wxDebugContext::CallerMemPos (const char * buf)
  507. {
  508.     return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType));
  509. }
  510.  
  511.  
  512. char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size)
  513. {
  514.     return CallerMemPos (buf) + PaddedSize (size);
  515. }
  516.  
  517.  
  518. /*
  519.   Slightly different as this takes a pointer to the start of the caller
  520.   requested region and returns a pointer to the start of the buffer.
  521.   */
  522. char * wxDebugContext::StartPos (const char * caller)
  523. {
  524.     return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) -
  525.             wxDebugContext::PaddedSize (sizeof (wxMemStruct))));
  526. }
  527.  
  528. /*
  529.   We may need padding between various parts of the allocated memory.
  530.   Given a size of memory, this returns the amount of memory which should
  531.   be allocated in order to allow for alignment of the following object.
  532.  
  533.   I don't know how portable this stuff is, but it seems to work for me at
  534.   the moment. It would be real nice if I knew more about this!
  535.  
  536.   // Note: this function is now obsolete (along with CalcAlignment)
  537.   // because the calculations are done statically, for greater speed.
  538. */
  539. size_t wxDebugContext::GetPadding (const size_t size)
  540. {
  541.     size_t pad = size % CalcAlignment ();
  542.     return (pad) ? sizeof(wxMarkerType) - pad : 0;
  543. }
  544.  
  545. size_t wxDebugContext::PaddedSize (const size_t size)
  546. {
  547.     // Added by Terry Farnham <TJRT@pacbell.net> to replace
  548.     // slow GetPadding call.
  549.     int padb;
  550.  
  551.     padb = size & m_balignmask;
  552.     if(padb)
  553.         return(size + m_balign - padb);
  554.     else
  555.         return(size);
  556. }
  557.  
  558. /*
  559.   Returns the total amount of memory which we need to get from the system
  560.   in order to satisfy a caller request. This includes space for the struct
  561.   plus markers and the caller's memory as well.
  562. */
  563. size_t wxDebugContext::TotSize (const size_t reqSize)
  564. {
  565.     return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) +
  566.             2 * sizeof(wxMarkerType));
  567. }
  568.  
  569.  
  570. /*
  571.   Traverse the list of nodes executing the given function on each node.
  572. */
  573. void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from)
  574. {
  575.   if (!from)
  576.     from = wxDebugContext::GetHead ();
  577.  
  578.   wxMemStruct * st = NULL;
  579.   for (st = from; st != 0; st = st->m_next)
  580.   {
  581.       void* data = st->GetActualData();
  582. //      if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
  583.       if (data != (void*) wxLog::GetActiveTarget())
  584.       {
  585.         (st->*func) ();
  586.       }
  587.   }
  588. }
  589.  
  590.  
  591. /*
  592.   Print out the list.
  593.   */
  594. bool wxDebugContext::PrintList (void)
  595. {
  596. #ifdef __WXDEBUG__
  597.   TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
  598.  
  599.   return TRUE;
  600. #else
  601.   return FALSE;
  602. #endif
  603. }
  604.  
  605. bool wxDebugContext::Dump(void)
  606. {
  607. #ifdef __WXDEBUG__
  608.   {
  609.     wxChar* appName = (wxChar*) wxT("application");
  610.     wxString appNameStr("");
  611.     if (wxTheApp)
  612.     {
  613.         appNameStr = wxTheApp->GetAppName();
  614.         appName = WXSTRINGCAST appNameStr;
  615.         wxLogMessage(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
  616.     }
  617.     else
  618.     {
  619.       wxLogMessage( wxT("----- Memory dump -----") );
  620.     }
  621.   }
  622.  
  623.   TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
  624.  
  625.   wxLogMessage( wxT("") );
  626.   wxLogMessage( wxT("") );
  627.  
  628.   return TRUE;
  629. #else
  630.   return FALSE;
  631. #endif
  632. }
  633.  
  634. #ifdef __WXDEBUG__
  635. struct wxDebugStatsStruct
  636. {
  637.   long instanceCount;
  638.   long totalSize;
  639.   wxChar *instanceClass;
  640.   wxDebugStatsStruct *next;
  641. };
  642.  
  643. static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name)
  644. {
  645.   while (st)
  646.   {
  647.     if (wxStrcmp(st->instanceClass, name) == 0)
  648.       return st;
  649.     st = st->next;
  650.   }
  651.   return NULL;
  652. }
  653.  
  654. static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
  655. {
  656.   st->next = head;
  657.   return st;
  658. }
  659. #endif
  660.  
  661. bool wxDebugContext::PrintStatistics(bool detailed)
  662. {
  663. #ifdef __WXDEBUG__
  664.   {
  665.     wxChar* appName = (wxChar*) wxT("application");
  666.     wxString appNameStr(wxT(""));
  667.     if (wxTheApp)
  668.     {
  669.         appNameStr = wxTheApp->GetAppName();
  670.         appName = WXSTRINGCAST appNameStr;
  671.         wxLogMessage(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
  672.     }
  673.     else
  674.     {
  675.       wxLogMessage( wxT("----- Memory statistics -----") );
  676.     }
  677.   }
  678.  
  679.   bool currentMode = GetDebugMode();
  680.   SetDebugMode(FALSE);
  681.  
  682.   long noNonObjectNodes = 0;
  683.   long noObjectNodes = 0;
  684.   long totalSize = 0;
  685.  
  686.   wxDebugStatsStruct *list = NULL;
  687.  
  688.   wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
  689.   if (!from)
  690.     from = wxDebugContext::GetHead ();
  691.  
  692.   wxMemStruct *st;
  693.   for (st = from; st != 0; st = st->m_next)
  694.   {
  695.     void* data = st->GetActualData();
  696.     if (detailed && (data != (void*) wxLog::GetActiveTarget()))
  697.     {
  698.       wxChar *className = (wxChar*) wxT("nonobject");
  699.       if (st->m_isObject && st->GetActualData())
  700.       {
  701.         wxObject *obj = (wxObject *)st->GetActualData();
  702.         if (obj->GetClassInfo()->GetClassName())
  703.           className = (wxChar*)obj->GetClassInfo()->GetClassName();
  704.       }
  705.       wxDebugStatsStruct *stats = FindStatsStruct(list, className);
  706.       if (!stats)
  707.       {
  708.         stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct));
  709.         stats->instanceClass = className;
  710.         stats->instanceCount = 0;
  711.         stats->totalSize = 0;
  712.         list = InsertStatsStruct(list, stats);
  713.       }
  714.       stats->instanceCount ++;
  715.       stats->totalSize += st->RequestSize();
  716.     }
  717.  
  718.     if (data != (void*) wxLog::GetActiveTarget())
  719.     {
  720.         totalSize += st->RequestSize();
  721.         if (st->m_isObject)
  722.             noObjectNodes ++;
  723.         else
  724.             noNonObjectNodes ++;
  725.     }
  726.   }
  727.  
  728.   if (detailed)
  729.   {
  730.     while (list)
  731.     {
  732.       wxLogMessage(wxT("%ld objects of class %s, total size %ld"),
  733.           list->instanceCount, list->instanceClass, list->totalSize);
  734.       wxDebugStatsStruct *old = list;
  735.       list = old->next;
  736.       free((char *)old);
  737.     }
  738.     wxLogMessage(wxT(""));
  739.   }
  740.  
  741.   SetDebugMode(currentMode);
  742.  
  743.   wxLogMessage(wxT("Number of object items: %ld"), noObjectNodes);
  744.   wxLogMessage(wxT("Number of non-object items: %ld"), noNonObjectNodes);
  745.   wxLogMessage(wxT("Total allocated size: %ld"), totalSize);
  746.   wxLogMessage(wxT(""));
  747.   wxLogMessage(wxT(""));
  748.  
  749.   return TRUE;
  750. #else
  751.   (void)detailed;
  752.   return FALSE;
  753. #endif
  754. }
  755.  
  756. bool wxDebugContext::PrintClasses(void)
  757. {
  758.   {
  759.     wxChar* appName = (wxChar*) wxT("application");
  760.     wxString appNameStr(wxT(""));
  761.     if (wxTheApp)
  762.     {
  763.         appNameStr = wxTheApp->GetAppName();
  764.         appName = WXSTRINGCAST appNameStr;
  765.         wxLogMessage(wxT("----- Classes in %s -----"), appName);
  766.     }
  767.   }
  768.  
  769.   int n = 0;
  770.   wxNode *node;
  771.   wxClassInfo *info;
  772.  
  773.   wxClassInfo::sm_classTable->BeginFind();
  774.   node = wxClassInfo::sm_classTable->Next();
  775.   while (node)
  776.   {
  777.     info = (wxClassInfo *)node->Data();
  778.     if (info->GetClassName())
  779.     {
  780.         wxString msg(info->GetClassName());
  781.         msg += wxT(" ");
  782.  
  783.         if (info->GetBaseClassName1() && !info->GetBaseClassName2())
  784.         {
  785.             msg += wxT("is a ");
  786.             msg += info->GetBaseClassName1();
  787.         }
  788.         else if (info->GetBaseClassName1() && info->GetBaseClassName2())
  789.         {
  790.             msg += wxT("is a ");
  791.             msg += info->GetBaseClassName1() ;
  792.             msg += wxT(", ");
  793.             msg += info->GetBaseClassName2() ;
  794.         }
  795.         if (info->GetConstructor())
  796.             msg += wxT(": dynamic");
  797.  
  798.         wxLogMessage(msg);
  799.     }
  800.     node = wxClassInfo::sm_classTable->Next();
  801.     n ++;
  802.   }
  803.   wxLogMessage(wxT(""));
  804.   wxLogMessage(wxT("There are %d classes derived from wxObject."), n);
  805.   wxLogMessage(wxT(""));
  806.   wxLogMessage(wxT(""));
  807.   return TRUE;
  808. }
  809.  
  810. void wxDebugContext::SetCheckpoint(bool all)
  811. {
  812.   if (all)
  813.     checkPoint = NULL;
  814.   else
  815.     checkPoint = m_tail;
  816. }
  817.  
  818. // Checks all nodes since checkpoint, or since start.
  819. int wxDebugContext::Check(bool checkAll)
  820. {
  821.   int nFailures = 0;
  822.  
  823.   wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
  824.   if (!from || checkAll)
  825.     from = wxDebugContext::GetHead ();
  826.  
  827.   for (wxMemStruct * st = from; st != 0; st = st->m_next)
  828.   {
  829.     if (st->AssertIt ())
  830.       nFailures += st->CheckBlock ();
  831.     else
  832.       return -1;
  833.   }
  834.  
  835.   return nFailures;
  836. }
  837.  
  838. // Count the number of non-wxDebugContext-related objects
  839. // that are outstanding
  840. int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint)
  841. {
  842.   int n = 0;
  843.  
  844.   wxMemStruct *from = NULL;
  845.   if (sinceCheckpoint && checkPoint)
  846.     from = checkPoint->m_next;
  847.   else
  848.     from = wxDebugContext::GetHead () ;
  849.  
  850.   for (wxMemStruct * st = from; st != 0; st = st->m_next)
  851.   {
  852.       void* data = st->GetActualData();
  853.       if (data != (void*) wxLog::GetActiveTarget())
  854.           n ++;
  855.   }
  856.  
  857.   return n ;
  858. }
  859.  
  860. #if USE_THREADSAFE_MEMORY_ALLOCATION
  861. static bool memSectionOk = FALSE;
  862.  
  863. class MemoryCriticalSection : public wxCriticalSection
  864. {
  865. public:
  866.     MemoryCriticalSection() {
  867.         memSectionOk = TRUE;
  868.     }
  869. };
  870.  
  871. class MemoryCriticalSectionLocker
  872. {
  873. public:
  874.     inline MemoryCriticalSectionLocker(wxCriticalSection& critsect)
  875.     : m_critsect(critsect), m_locked(memSectionOk) { if(m_locked) m_critsect.Enter(); }
  876.     inline ~MemoryCriticalSectionLocker() { if(m_locked) m_critsect.Leave(); }
  877.  
  878. private:
  879.     // no assignment operator nor copy ctor
  880.     MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker&);
  881.     MemoryCriticalSectionLocker& operator=(const MemoryCriticalSectionLocker&);
  882.  
  883.     wxCriticalSection& m_critsect;
  884.     bool    m_locked;
  885. };
  886.  
  887. static MemoryCriticalSection memLocker;
  888. #endif
  889.  
  890. // TODO: store whether this is a vector or not.
  891. void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
  892. {
  893. #if USE_THREADSAFE_MEMORY_ALLOCATION
  894.   MemoryCriticalSectionLocker lock(memLocker);
  895. #endif
  896.  
  897.   // If not in debugging allocation mode, do the normal thing
  898.   // so we don't leave any trace of ourselves in the node list.
  899.  
  900. #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
  901. // VA 3.0 still has trouble in here
  902.   return (void *)malloc(size);
  903. #endif
  904.   if (!wxDebugContext::GetDebugMode())
  905.   {
  906.     return (void *)malloc(size);
  907.   }
  908.  
  909.     int totSize = wxDebugContext::TotSize (size);
  910.     char * buf = (char *) malloc(totSize);
  911.     if (!buf) {
  912.         wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size);
  913.         return 0;
  914.     }
  915.     wxMemStruct * st = (wxMemStruct *)buf;
  916.     st->m_firstMarker = MemStartCheck;
  917.     st->m_reqSize = size;
  918.     st->m_fileName = fileName;
  919.     st->m_lineNum = lineNum;
  920.     st->m_id = MemStructId;
  921.     st->m_prev = 0;
  922.     st->m_next = 0;
  923.     st->m_isObject = isObject;
  924.  
  925.     // Errors from Append() shouldn't really happen - but just in case!
  926.     if (st->Append () == 0) {
  927.         st->ErrorMsg ("Trying to append new node");
  928.     }
  929.  
  930.     if (wxDebugContext::GetCheckPrevious ()) {
  931.         if (st->CheckAllPrevious () < 0) {
  932.             st->ErrorMsg ("Checking previous nodes");
  933.         }
  934.     }
  935.  
  936.     // Set up the extra markers at the middle and end.
  937.     char * ptr = wxDebugContext::MidMarkerPos (buf);
  938.     * (wxMarkerType *) ptr = MemMidCheck;
  939.     ptr = wxDebugContext::EndMarkerPos (buf, size);
  940.     * (wxMarkerType *) ptr = MemEndCheck;
  941.  
  942.     // pointer returned points to the start of the caller's
  943.     // usable area.
  944.     void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
  945.     st->m_actualData = m_actualData;
  946.  
  947.     return m_actualData;
  948. }
  949.  
  950. // TODO: check whether was allocated as a vector
  951. void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
  952. {
  953. #if USE_THREADSAFE_MEMORY_ALLOCATION
  954.   MemoryCriticalSectionLocker lock(memLocker);
  955. #endif
  956.  
  957.   if (!buf)
  958.     return;
  959.  
  960. #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
  961. // VA 3.0 still has trouble in here
  962.   free((char *)buf);
  963. #endif
  964.   // If not in debugging allocation mode, do the normal thing
  965.   // so we don't leave any trace of ourselves in the node list.
  966.   if (!wxDebugContext::GetDebugMode())
  967.   {
  968.     free((char *)buf);
  969.     return;
  970.   }
  971.  
  972.     // Points to the start of the entire allocated area.
  973.     char * startPointer = wxDebugContext::StartPos ((char *) buf);
  974.     // Find the struct and make sure that it's identifiable.
  975.     wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
  976.  
  977.     if (! st->ValidateNode ())
  978.         return;
  979.  
  980.     // If this is the current checkpoint, we need to
  981.     // move the checkpoint back so it points to a valid
  982.     // node.
  983.     if (st == wxDebugContext::checkPoint)
  984.       wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
  985.  
  986.     if (! st->Unlink ())
  987.     {
  988.       st->ErrorMsg ("Unlinking deleted node");
  989.     }
  990.  
  991.     // Now put in the fill char into the id slot and the caller requested
  992.     // memory locations.
  993.     st->SetDeleted ();
  994.     (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
  995.                    st->RequestSize ());
  996.  
  997.     free((char *)st);
  998. }
  999.  
  1000. // Trace: send output to the current debugging stream
  1001. void wxTrace(const wxChar * ...)
  1002. {
  1003. #if 1
  1004.     wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
  1005. #else
  1006.     va_list ap;
  1007.   static wxChar buffer[512];
  1008.  
  1009.   va_start(ap, fmt);
  1010.  
  1011. #ifdef __WXMSW__
  1012.   wvsprintf(buffer,fmt,ap) ;
  1013. #else
  1014.   vsprintf(buffer,fmt,ap) ;
  1015. #endif
  1016.  
  1017.   va_end(ap);
  1018.  
  1019.   if (wxDebugContext::HasStream())
  1020.   {
  1021.     wxDebugContext::GetStream() << buffer;
  1022.     wxDebugContext::GetStream().flush();
  1023.   }
  1024.   else
  1025. #ifdef __WXMSW__
  1026. #ifdef __WIN32__
  1027.     OutputDebugString((LPCTSTR)buffer) ;
  1028. #else
  1029.     OutputDebugString((const char*) buffer) ;
  1030. #endif
  1031. #else
  1032.     fprintf(stderr, buffer);
  1033. #endif
  1034. #endif
  1035. }
  1036.  
  1037. // Trace with level
  1038. void wxTraceLevel(int, const wxChar * ...)
  1039. {
  1040. #if 1
  1041.     wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
  1042. #else
  1043.   if (wxDebugContext::GetLevel() < level)
  1044.     return;
  1045.  
  1046.   va_list ap;
  1047.   static wxChar buffer[512];
  1048.  
  1049.   va_start(ap, fmt);
  1050.  
  1051. #ifdef __WXMSW__
  1052.   wxWvsprintf(buffer,fmt,ap) ;
  1053. #else
  1054.   vsprintf(buffer,fmt,ap) ;
  1055. #endif
  1056.  
  1057.   va_end(ap);
  1058.  
  1059.   if (wxDebugContext::HasStream())
  1060.   {
  1061.     wxDebugContext::GetStream() << buffer;
  1062.     wxDebugContext::GetStream().flush();
  1063.   }
  1064.   else
  1065. #ifdef __WXMSW__
  1066. #ifdef __WIN32__
  1067.     OutputDebugString((LPCTSTR)buffer) ;
  1068. #else
  1069.     OutputDebugString((const char*) buffer) ;
  1070. #endif
  1071. #else
  1072.     fprintf(stderr, buffer);
  1073. #endif
  1074. #endif
  1075. }
  1076.  
  1077. #else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
  1078. void wxTrace(const char *WXUNUSED(fmt) ...)
  1079. {
  1080. }
  1081.  
  1082. void wxTraceLevel(int WXUNUSED(level), const char *WXUNUSED(fmt) ...)
  1083. {
  1084. }
  1085. #endif
  1086.  
  1087.