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