На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
15 мая "Исходники.РУ" отмечают 20-летие присутствия в сети!
Поздравляем всех причастных и неравнодушных с юбилеем сайта!
И огромное спасибо всем, кто был с нами все эти годы!
msm.ru
! Правила раздела "Наши Исходники"
Раздел предназначен для публикации различных исходников и программных решений (в виде исходных текстов), которые Вы считаете достойными внимания и/или интересными. Язык исходника значения не имеет. Это может быть C/C++, Pascal, Perl, PHP, C#, Foth, Prolog или любой другой существующий язык программирования. Единственный момент – в названии темы этот язык должен быть указан. Например, «[C++] Представление чисел в римской записи». Сам исходный текст должен содержаться в первом посте темы. Если исходник занимает не больше одного-двух экранов, то допустимо его публикация непосредственно в посте. Иначе исходный текст должен быть прикреплен к посту в виде архива. Кроме того, первый пост должен содержать:

- Информацию о платформе/компиляторе, для которых предназначен исходный текст (если эта информация существенна)
- Ссылку на оригинал и автора (если публикуется чужой исходный текст)
- Максимально подробное описание – какую задачу решает опубликованный исходный текст, и чем он интересен.

Плагиат крайне не приветствуется. Также не приветствуется публикация исходных текстов вирусов, крэков и т. п. информации. Это элементарно противозаконно.

Для быстрого поиска нужного исходника можно воспользоваться навигатором:
Быстрый поиск по разделу
  
> [C++] Ищем утечки памяти new/delete
    В принципе, много копий поломано в поиске утечек памяти. Предлагаю свой простенький вариант. Не очень оптимальный, но в принципе, юзабельный.
    В данном случае будем рассматривать операторы new и delete. Т.е. где-то память выделили оператором new, а delete вызвать забыли.
    Для начала переопределим их. Например, так:
    ExpandedWrap disabled
      // где-то в memleaks_detect.h
      inline void * __cdecl operator new(size_t size)
      {
          return (void *)LocalAlloc(LMEM_ZEROINIT, size);
      }
       
      inline void __cdecl operator delete(void *ptr)
      {
          LocalFree(ptr);
      }

    Отлично. У нас есть макросы __FILE__, __LINE__, но они нас не спасут, ибо будут всегда указывать на этот файл. И в выводе мы увидим нечто вроде:
    ExpandedWrap disabled
      Called new operator from memleaks.h:2
      Called delete operator from memleaks.h:7

    Нехорошо. Но у нас есть pdb-файл, в котором хранится соответствие адресов и исходных текстов. И мы можем узнать адрес, откуда нас вызвали. Например, так:
    ExpandedWrap disabled
          PVOID _caller;
          __asm
          {
              mov eax, [esp+4];
              mov _caller, eax;
          }
    .
    Теперь у нас есть адрес, где вызвали оператор new, по которому можно понять из pdb или прямо в отладчике, конкретное место в исходном тексте (например, в MS VS 2008 достаточно перейти на страничку Disassembly и там вбить адрес инструкции. Например, такой: 0x0047a4f8. И мы перескочим на интересующее нас место исходном коде).

    Далее.
    Оператор new и оператор delete должны работать с одним и тем же указателем. Они также могут вызываться несколько раз подряд из одного и того же места. Чтобы не загромождать вывод дублирующимися записями, будем вести счетчик для каждого вызова для конкретного адреса, увеличивать его при вызове new и уменьшать при вызове delete. Если счетчик к концу работы приложения стал равен нулю, то все отлично, утечки нет. В ином случае - проблема. Надо искать ее истоки.
    Итак, создадим массив, куда будем складывать информацию о выделениях памяти. Тут, в принципе, можно было бы обойтись, например, односвязным списком (и работает быстрее, и памяти меньше ест, и "дефрагментация" массива будет сведена к нулю), но морочиться не хотелось и я обошелся обычным массивом. Впрочем, кто-то может оптимизировать и сделать на одно/двухсвязных списках.
    Итак:
    ExpandedWrap disabled
      // memleak.h
      #define SIZE_OF_MEMLEAK                    1000 // количество элементов в массиве. Чем больше - тем лучше, но тем и тормознее, ибо перебирать массив надо будет долго
       
      extern ULONGLONG mem_counter;
      extern PMEMLEAK MemLeakBuffer;
       
      BOOL AllocMemLeakBuffer();                  // создаем буфер для массива
      ULONG AllocMemLeakIndex(PVOID caller);      // ищем индекс в массиве для оператора new. Если элемент в массиве с адресом _caller не найден, то выделяем из пула свободных новый элемент
      BOOL FreeMemLeakIndex(ULONG index);         // уменьшаем счетчик для данного _caller. Если counter стал равен нулю, то освобождаем элемент
      VOID FreeMemLeakBuffer();                   // в конце программы освобождаем буфер
       
      typedef struct _tagMEMLEAK
      {
          ULONG       counter;            // количество вызовов new для данного _caller
          PVOID       caller;             // непосредственно адрес
      } MEMLEAK, *PMEMLEAK;


    Теперь сами ф-ции подсчета:
    (поскольку рассматриваю винду, то и пользуюсь ее ф-циями выделения памяти под массив. В ином случае можно использовать любой аллокатор памяти)
    ExpandedWrap disabled
      // memleak.cpp
      PMEMLEAK MemLeakBuffer;
       
      BOOL AllocMemLeakBuffer()
      {
          MemLeakBuffer = (PMEMLEAK) LocalAlloc(LMEM_ZEROINIT, SIZE_OF_MEMLEAK*sizeof(MEMLEAK));
          return ( NULL != MemLeakBuffer);
      }
       
      ULONG AllocMemLeakIndex(PVOID caller)
      {
          ULONG free = -1;                     // если вдруг не найдем _caller, то будем хотя бы иметь индекс свободного элемента в массиве, дабы не перебирать его еще раз
          for(ULONG c = 0; c < SIZE_OF_MEMLEAK; ++c)
              if ( caller == MemLeakBuffer[c].caller )   // _caller нашли, увеличиваем счетчик и возвращаем индекс элемента
              {  
                  MemLeakBuffer[c].counter++;
                  return c;
              }
              else if ( -1 == free && !MemLeakBuffer[c].caller ) free = c;
       
              if ( free != -1 ) { MemLeakBuffer[free].caller = caller; MemLeakBuffer[free].counter++; }  // не нашли. Присваиваем элементу _caller и увеличиваем счетчик.
          return free;
      }
       
      BOOL FreeMemLeakIndex(ULONG index)
      {
          if ( index < SIZE_OF_MEMLEAK )
          {
              MemLeakBuffer[index].counter--;     // вызвали оператор delete. Уменьшаем счетчик. Если стал равен нулю, то обнуляем _caller, тем самым освобождая элемент для будущего использования
              if ( !MemLeakBuffer[index].counter ) MemLeakBuffer[index].caller = NULL;
              return TRUE;
          }
          return FALSE;
      }
       
      void FreeMemLeakBuffer()
      {
          LocalFree(MemLeakBuffer);
      }


    В данный момент проверок мало, но и детектор у нас простой. Во-первых, память может в программе повредиться и мы получим неверный index. В следствие чего процедура FreeMemLeakIndex() будет работать неведомо как. Кроме того, в AllocMemLeakBuffer вызывается ф-ция LocalAlloc с флагом LMEM_ZEROINIT и поэтому нулями выделенную память мы не инициализируем. В иных случаях - следовало бы.
    И еще момент: поскольку нам неизвестно, откуда будут вызываться new и delete, то по хорошему надо сделать синхронизацию вызовов между потоками (например critical_sections), ибо один поток получит индекс свободного элемента, а второй в это время в него чего-нибудь да запишет, опередив первый).
    Собрав все имеющееся в одно целое, определим свои new и delete:
    ExpandedWrap disabled
      inline void * __cdecl operator new(size_t size)
      {
          PVOID _caller;
          __asm
          {
              mov eax, [esp+4];
              mov _caller, eax;
          }
       
          PVOID buf = LocalAlloc(LMEM_ZEROINIT, size + 4);      // выделяем память для запросившего ее + sizeof(ULONG) для сохранения индекса, к которому относится _caller
          ULONG index = AllocMemLeakIndex(_caller);             // добавляем новый элемент или увеличиваем счетчик
          *PULONG(buf) = index;                                 // сохраняем наш индекс в выделенной памяти
          mem_counter++;                                        // увеличиваем общий счетчик вызовов new
          return PVOID(ULONG(buf)+4);                               // и возвращаем вызвавшему указатель на выделенную память со смещением от нашего счетчика
      }
       
      inline void __cdecl operator delete(void *ptr)
      {
          mem_counter--;                                        // уменьшаем глобальный счетчик
          ptr = PVOID(ULONG(ptr)-4);                            // получаем _правильный_ указатель на память, где в начале у нас хранится индекс
          ULONG index = *PULONG(ptr);                           // получаем этот индекс
          FreeMemLeakIndex(index);                              // уменьшаем счетчик
          LocalFree(ptr);                                           // и освобождаем память
      }


    Ну и соответственно, делаем поправки в нашей программе следующим образом:
    ExpandedWrap disabled
      int main(int argc, char ** argv)
      {
             AllocMemLeakBuffer();
             mem_counter = 0;
       
             DoSomething(); // основной ход нашей программы
       
             if ( mem_counter > 0 )
             {
                   printf("Memory leaks was detected. 'delete' was not called %d times.\n\n"
                            "Following addresses are affected:\n", mem_counter);
                   for(int c = 0; c < SIZE_OF_MEMLEAK; ++i)
                        if ( MemLeakBuffer[c].caller )
                          printf("Address: 0x%08x; Count: %d\n", MemLeakBuffer[c].caller, MemLeakBuffer[c].counter);
             }
             FreeMemLeakBuffer();
      }


    Добавляем где нужно
    ExpandedWrap disabled
      #ifdef _DEBUG

    и отлаживаем в поисках утечек. Исходников не прикладываю (лениво). Но собрать воедино - несложно.
    Как итоги:
    - Плюсы: не надо лазить в листингах вызовов new. Все уже отсортировано и разложено по полочкам. Поэтому если Вы не маньяк и не выделяете на каждом шагу память, то адресов будет немного. И будет показано, сколько раз выделяли память.
    - Минусы: при большом количестве выделений памяти в разных местах (если этих мест больше 1000, как в нашем примере), будет плохо. Если массив большой, а вызовов также много, программа будет едва ворочаться при отладке. Плюс не учитывались синхронизация и проверки "порчи" памяти.

    В принципе, мне функционала хватило, чтобы отладить программы. Даже очень большие по объему.

    Всем спасибо за внимание. Жду комментариев, критику и похвалу. :)
    user posted image
    ЩИТО?
      Гм. Мне казалось, что такую мелочь точно не стоит тут выкладывать. Я этих перегрузок new/delete/malloc/free с десяток, наверно, написал и успешно удалил после выполнения их задачи
      Это как функция вывода сообщения с ошибкой для отладки, чисто временные пару строчек кода
      const char *out = "|*0>78-,+<|"; size_t cc = char_traits<char>::length(out);
      for (size_t i=0;i<cc;i++){cout<<static_cast<char>((out[i]^89));}cout<<endl;


      user posted image Чат Исходников в СкайпеНе тормози, форум теперь здесь!Чат Исходников в Дискорде
        Цитата B.V. @
        Гм. Мне казалось, что такую мелочь точно не стоит тут выкладывать. Я этих перегрузок new/delete/malloc/free с десяток, наверно, написал и успешно удалил после выполнения их задачи
        Это как функция вывода сообщения с ошибкой для отладки, чисто временные пару строчек кода

        Разумеется, мелочь. Но приятная. :) Суть этой мелочи в том, что не нужно менять уже сформированный код, добавлять какие-то проверки и т.д. Просто включил директиву, код подключился, показал промежуточные состояния работы и завершился. Данный опус не претендует на решение всех проблем человечества, но основные понятия отлова таких ситуаций, мне кажется, дает.
        Быть может, кому и пригодится. :)
        user posted image
        ЩИТО?
          пользуюсь вот такой штучкой
          ExpandedWrap disabled
            #ifdef USE_LEAK_WATCHER
                int tmpDbgFlag;
                tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
                tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;
                _CrtSetDbgFlag(tmpDbgFlag);
            #endif

          Очень доволен.
          http://2monkeys.ru/
            Цитата ALXR @
            ... И мы можем узнать адрес, откуда нас вызвали. Например, так:
            ExpandedWrap disabled
                  PVOID _caller;
                  __asm
                  {
                      mov eax, [esp+4];
                      mov _caller, eax;
                  }
            .
            Теперь у нас есть адрес, где вызвали оператор new, по которому можно понять из pdb или прямо в отладчике, конкретное место в исходном тексте...

            ALXR, вот это место:
            ExpandedWrap disabled
              mov eax, [esp+4];


            А почему +4 ?

            Кроме того, можно обойтись без ассемблера. А это значит, что при возможном переходе к x64
            будет получен бонус.
            Приблизительно так:
            ExpandedWrap disabled
              void * __cdecl operator new(size_t size)
              {
               size_t _caller = ((size_t*)&_caller)[2];
              //...
            Сообщение отредактировано: ЫукпШ -
            Подпись была выключена в связи с наложенным заземлением.
              Особенность такой задачи состоит в том, что вызовы new начинаются ещё из startup-а,
              до инициализации любых библиотек и до старта основной программы.
              А у delete - наоборот. Некоторые вызовы производятся после смерти основной программы
              и после гибели стандартных процедур из библиотек.
              Поэтому пришлось некоторые необходимые процедуры вывода реализовать самостоятельно
              и целиком внести в исходник. Иначе в некоторых случаях выполнение такой программы происходило
              очень странным образом. (Тем более, что стандартные процедуры вывода
              тоже могут использовать new/delete.)
              В итоге получилось так:
              Скрытый текст

              ExpandedWrap disabled
                // ---------------------------------------------------------------------------------
                // file 000ndTests3.h 2017.03.13
                // new-delete research test
                // ---------------------------------------------------------------------------------
                #include "stdafx.h"
                // ---------------------------------------------------------------------------------
                #ifndef _000ndTests3_H_2017_03_13
                #define _000ndTests3_H_2017_03_13
                 
                // .................................................................................
                // Пример использования может быть таким:
                //
                //#include "stdafx.h"
                //
                ///#define SIZE_RESEARCH_NEW 32*1024
                //#define LCOUNT_RESEARCH_NEW 10
                //#define TYPEKEY_RESEARCH_NEW true
                //#include "000ndTests3.h"
                //
                //using namespace std;
                //
                //int __cdecl _tmain(void)
                //{
                //  int* p = new int [256];
                // _tprintf(_T("Hello, world!\n"));
                // return 0;
                //}
                //
                // Вывод диагностики будет производиться в окно утилиты "Dbgview" от SysInternals.
                // Старт работы сопровождается сообщением "----- new-delete research start -----".
                // Отсутствие ошибок сопровождается сообщением "----- new-delete errors not found -----"
                // и значением ErrorsCount=0.
                // В случае недостаточного размера массивов и невозможности заносить туда информацию
                // выдаётся соообщение об ошибке:
                // "********************************* Add addr error, (new) p=... size=%d caller=...".
                // В этом случае исследование бессмысленно, надо увеличить размер массивов
                // посредством увеличения параметра SIZE_RESEARCH_NEW и продолжить исследование.
                // В случае попытки удаления блока памяти, адрес которого отсутствует в массиве,
                // (например при повторном вызове delete) выдаётся сообщение об ошибке:
                // "********************************* Delete addr error p=... caller=...".
                //
                // .................................................................................
                 
                // ---------------------------------------------------------------------------------
                // new[]     -> new    -> malloc
                // delete [] -> delete -> free
                // ---------------------------------------------------------------------------------
                 
                #ifndef SIZE_RESEARCH_NEW
                // Размер массива хранения адресов памяти и адресов вызова.
                // Параметр может быть переопределён исследуемой программой.
                #define SIZE_RESEARCH_NEW 16*1024
                #endif
                 
                 
                #ifndef MESS_RESEARCH_NEW
                // Количество диагностических сообщений операций добавления/удаления данных в массив.
                // Параметр может быть переопределён исследуемой программой.
                #define MESS_RESEARCH_NEW 5
                #endif
                 
                 
                #ifndef LCOUNT_RESEARCH_NEW
                // Количество диагностических сообщений.
                // Параметр может быть переопределён исследуемой программой.
                // Если сообщения не получены вообще, это означает, что число
                // ошибок превышает это значение.
                // В этом случае следует увеличить это значение
                // опытным путём для конкретного исследования.
                //
                #define LCOUNT_RESEARCH_NEW 5
                #endif
                 
                #ifndef TYPEKEY_RESEARCH_NEW
                // форма вывода диагностики.
                // Параметр может быть переопределён исследуемой программой.
                #define TYPEKEY_RESEARCH_NEW true
                #endif
                 
                // Критическая секция для синхронизации - на случай работы в много-поточной среде.
                CRITICAL_SECTION CrSeo;
                // ключ формы вывода диагностики
                static volatile bool keyotype=TYPEKEY_RESEARCH_NEW;
                // ключ инициализации
                static volatile bool keyo=false;
                // Счётчик занятых объектов памяти - он же общее число ошибок после окончания роботы.
                static volatile UINT uiCounto=0;
                // Объём массивов адресов выделенной памяти и адресов возврата.
                static const size_t SIZEpo = SIZE_RESEARCH_NEW;//64*1024;//1024*1024;
                // Массив адресов выделенной памяти.
                void* poiso   [SIZEpo];
                // Массив размеров блоков выделенной памяти.
                size_t sizemem [SIZEpo];
                // Массив адресов возврата в процедуру, вызвавшую new.
                void* pcaller [SIZEpo];
                // счётчик числа сообщений об ошибках типа "Add"
                static volatile UINT uiCountAdd=0;
                // счётчик числа сообщений об ошибках типа "Delete"
                static volatile UINT uiCountDel=0;
                 
                // Константа получения адреса возврата.
                #ifdef _M_IX86
                const size_t RET_ADDR_STACK_OFFSET = 2;
                #endif
                #ifdef _M_AMD64
                const size_t RET_ADDR_STACK_OFFSET = 3;
                #endif
                 
                char typebuff[256];
                 
                 
                // ---------------------------------------------------------------------------------
                namespace SimpleRs
                {
                // ---------------------------------------------------------------------------------
                #ifdef _M_AMD64
                size_t WINAPI qword2asc (char* adata, size_t size, unsigned long long data);
                size_t WINAPI qword2asc (char* pStr, size_t sizeStr, const char* pInfo, unsigned long long data);
                #endif
                 
                size_t WINAPI dword2dec (char* pStr, size_t sizeStr, const char* pInfo, DWORD data);
                size_t WINAPI dword2dec (char* pStr, size_t sizeStr, DWORD b);
                size_t WINAPI Str_Len   (const char* pStr);
                size_t WINAPI str2str   (char* pStr, size_t sizeStr, const char* pInfo, const char* pData);
                size_t WINAPI Str_Cpy   (char* pTar, size_t sizeTar, const char* pSou);
                size_t WINAPI addr2asc  (char* pStr, size_t sizeStr, const char* pInfo, void* pData);
                size_t WINAPI dword2asc (char* adata,size_t size, DWORD data);
                size_t WINAPI dword2asc (char* pStr, size_t sizeStr, const char* pInfo, DWORD data);
                size_t WINAPI word2asc  (char* adata, size_t size, WORD data);
                size_t WINAPI byte2asc  (char* adata, size_t size, const char data);
                char WINAPI byte2asc_slave (char b);
                // ---------------------------------------------------------------------------------
                #ifdef _M_AMD64
                 
                size_t WINAPI qword2asc (char* adata, size_t size, unsigned long long data)
                {
                 if(!adata)   return 0;
                 if(size < 17) return 0;
                 size_t n = dword2asc (adata,size,(data >> 32));
                 adata += n;
                 dword2asc (adata,size-n,(data & 0x00000000FFFFFFFF));
                 return 16;
                }
                // ---------------------------------------------------------------------------------
                size_t WINAPI qword2asc (char* pStr, size_t sizeStr, const char* pInfo, unsigned long long data)
                {
                 if(!pStr)        return 0;
                 
                 size_t sizei = Str_Len(pInfo);
                 if(sizeStr < (sizei+16+1)) return 0;
                 
                 char* p = pStr;
                 
                 size_t n1 = str2str (p, sizeStr, pInfo, NULL);
                 p += n1;
                 sizeStr -= n1;
                 size_t n2 = qword2asc (p, sizeStr, data);
                 
                 return n1+n2;
                }
                 
                #endif
                // ---------------------------------------------------------------------------------
                char WINAPI byte2asc_slave (char b)
                {
                 if (b < 10){b += '0';}
                 else       {b += '7';}
                 return b;
                }
                // ---------------------------------------------------------------------------------
                size_t WINAPI byte2asc (char* adata, size_t size, const char data)
                {
                 if(!adata)   return 0;
                 if(size < 3) return 0;
                 *adata++ = byte2asc_slave ((UCHAR)data >> 4);
                 *adata++ = byte2asc_slave ((UCHAR)data & 0x0F);
                 *adata   = '\0';
                 return 2;
                }
                // ---------------------------------------------------------------------------------
                size_t WINAPI word2asc (char* adata, size_t size, WORD data)
                {
                 if(!adata)   return 0;
                 if(size < 5) return 0;
                 size_t n = byte2asc (adata,size,(char)(data >> 8));
                 adata += n;
                 byte2asc (adata,size-n,(char)(data & 0x00FF));
                 return 4;
                }
                // ---------------------------------------------------------------------------------
                size_t WINAPI dword2asc (char* adata,size_t size, DWORD data)
                {
                 if(!adata)   return 0;
                 if(size < 9) return 0;
                 size_t n = word2asc (adata,size,(data >> 16));
                 adata += n;
                 word2asc (adata,size-n,(data & 0x0000FFFF));
                 return 8;
                }
                // ---------------------------------------------------------------------------------
                size_t WINAPI addr2asc (char* pStr, size_t sizeStr, const char* pInfo, void* pData)
                {
                #ifdef _M_IX86
                 
                 if(!pStr)        return 0;
                 
                 size_t sizei = Str_Len(pInfo);
                 if(sizeStr < (sizei+8+1)) return 0;
                 
                 char* p = pStr;
                 
                 size_t n1 = str2str (p, sizeStr, pInfo, NULL);
                 p += n1;
                 sizeStr -= n1;
                 size_t n2 = dword2asc (p, sizeStr, (DWORD)pData);
                 
                 return n1+n2;
                 
                #endif
                 
                 
                #ifdef _M_AMD64
                 
                 if(!pStr)        return 0;
                 
                 size_t sizei = Str_Len(pInfo);
                 if(sizeStr < (sizei+16+1)) return 0;
                 
                 char* p = pStr;
                 
                 size_t n1 = str2str (p, sizeStr, pInfo, NULL);
                 p += n1;
                 sizeStr -= n1;
                 size_t n2 = qword2asc (p, sizeStr, (unsigned long long)pData);
                 
                 return n1+n2;
                 
                #endif
                }
                // ---------------------------------------------------------------------------------
                size_t WINAPI Str_Len(const char* pStr)
                {
                 if(!pStr) return 0;
                 size_t size=0;
                 for(size_t i=0;;++i)
                 {
                  if(pStr[i]=='\0') break;
                  ++size;
                 }
                 return size;
                }
                // ---------------------------------------------------------------------------------
                size_t WINAPI dword2dec (char* pStr, size_t sizeStr, const char* pInfo, DWORD data)
                {
                 if(!pStr)        return 0;
                 
                 size_t sizei = Str_Len(pInfo);
                 
                 char tmp[64];
                 size_t n2 = dword2dec (tmp, ARRAYSIZE(tmp), data);
                 if(sizeStr < (sizei+n2+1)) return 0;
                 
                 char* p = pStr;
                 
                 size_t n1 = str2str (p, sizeStr, pInfo, tmp);
                 return n1;
                }
                // ---------------------------------------------------------------------------------
                size_t WINAPI dword2dec (char* pStr, size_t sizeStr, DWORD b)
                {
                 if(!pStr)        return 0;
                 if(sizeStr < 11) return 0;
                 
                 DWORD i    = 0;
                 DWORD m    = 1000000000;
                 DWORD size = 10;
                 
                 for(i=0;i<(size+1);++i) { pStr[i]='\0'; }
                 
                 for(i=0;m!=0;++i)
                 {
                  pStr[i] = '0';
                  for(;m != 0;)
                  {
                   if(b >= m) { ++pStr[i]; b -= m; }
                   else       { m /= 10;  break;   }
                  }
                 }
                 DWORD spaces=0;
                 for(i=0;i<(size-1);++i)
                 {
                  if(pStr[i]!='0') break;
                  ++spaces;
                 }
                 DWORD ind = spaces;
                 DWORD count = size - spaces;
                 for(i=0;i<count;++i) { pStr[i] = pStr[ind++]; }
                 pStr[count] = '\0';
                 
                 return Str_Len(pStr);
                }
                // ---------------------------------------------------------------------------------
                size_t WINAPI str2str (char* pStr, size_t sizeStr, const char* pInfo, const char* pData)
                {
                 if(!pStr)        return 0;
                 if((!pInfo)&&(!pData)) return 0;
                 
                 size_t sizei = Str_Len(pInfo);
                 size_t sized = Str_Len(pData);
                 
                 if(sizeStr < (sizei+sized+1)) return 0;
                 
                 char* p = pStr;
                 
                 size_t ni = Str_Cpy(p, sizeStr, pInfo);
                 p += ni;
                 sizeStr -= ni;
                 
                 size_t nd = Str_Cpy(p, sizeStr, pData);
                 
                 return ni+nd;
                }
                // ---------------------------------------------------------------------------------
                size_t WINAPI Str_Cpy(char* pTar, size_t sizeTar, const char* pSou)
                {
                 if(!pTar) return 0;
                 if(!pSou) return 0;
                 size_t sizeSou = Str_Len(pSou);
                 if(sizeTar < (sizeSou+1)) return 0;
                 
                 size_t size=0;
                 for(size_t i=0;;++i)
                 {
                  pTar[i]=pSou[i];
                  if(pSou[i]=='\0') break;
                  ++size;
                 }
                 return size;
                }
                // ---------------------------------------------------------------------------------
                }
                // ---------------------------------------------------------------------------------
                // Добавим адрес выделенной памяти и адрес вызова new в массивы.
                bool addAddro(void* pAd, void* pc, size_t size)
                {
                 for(size_t i=0;i<SIZEpo;++i)
                 {
                  if(poiso[i]==NULL)
                  {
                   poiso[i]=pAd;
                   pcaller [i]=pc;
                   sizemem [i]=size;
                   return true;
                  }
                 }
                 return false;
                }
                // ---------------------------------------------------------------------------------
                // Удалим указанный адрес выделенной памяти из массива, если он там имеется.
                bool killAddro(void* pAd)
                {
                 for(size_t i=0;i<SIZEpo;++i)
                 {
                  if(poiso[i]==pAd) {poiso[i]=NULL; return true;}
                 }
                 return false;
                }
                // ---------------------------------------------------------------------------------
                // Узнаем заполненность массива адресов полученной памяти.
                size_t sizeAddro(void)
                {
                 size_t size=0;
                 for(size_t i=0;i<SIZEpo;++i)
                 {
                  if(poiso[i]!=NULL) {++size;}
                 }
                 return size;
                }
                // ---------------------------------------------------------------------------------
                // Вывод содержимого массива адресов полученной памяти и адресов вызова new.
                void typeAddrso(void)
                {
                 for(size_t i=0;i<SIZEpo;++i)
                 {
                  if(poiso[i]!=NULL)
                  {
                    char* pt     = typebuff;
                    size_t sizeS = ARRAYSIZE(typebuff);
                    size_t n     = 0;
                 
                    n = SimpleRs::dword2dec(pt, sizeS, "p[", (DWORD)i);
                    pt += n; sizeS -= n;
                 
                    n = SimpleRs::addr2asc(pt, sizeS, "]=0x", poiso[i]);
                    pt += n; sizeS -= n;
                 
                    n = SimpleRs::dword2dec(pt, sizeS, " size=", (DWORD)sizemem [i]);
                    pt += n; sizeS -= n;
                 
                    n = SimpleRs::dword2dec(pt, sizeS, " caller[", (DWORD)i);
                    pt += n; sizeS -= n;
                 
                    n = SimpleRs::addr2asc(pt, sizeS, "]=0x", pcaller[i]);
                //    pt += n; sizeS -= n;
                 
                     ::OutputDebugStringA(typebuff);
                  }
                 }
                }
                // ---------------------------------------------------------------------------------
                // Обработчик new.
                void* newroutineo(PVOID caller,size_t size)
                {
                 if(!keyo)
                 {
                  InitializeCriticalSection(&CrSeo);
                  keyo=true;
                  ::OutputDebugStringA(" ");
                  ::OutputDebugStringA("----- new-delete research start   -----");
                  for(size_t i=0;i<SIZEpo;++i) {poiso [i]=NULL;}
                 }
                 
                 EnterCriticalSection(&CrSeo);
                 
                 void *p = (void*)malloc(size);
                 if(p)
                 {
                  if(!addAddro(p,caller,size))
                  {
                   if(++uiCountAdd <= MESS_RESEARCH_NEW)
                   {
                    char* pt     = typebuff;
                    size_t sizeS = ARRAYSIZE(typebuff);
                    size_t n     = 0;
                 
                    n = SimpleRs::str2str (pt, sizeS, "*********************************"," Add addr error");
                    pt += n; sizeS -= n;
                 
                    n = SimpleRs::addr2asc(pt, sizeS, " p=0x", p);
                    pt += n; sizeS -= n;
                 
                    n = SimpleRs::dword2dec(pt, sizeS, " size=", (DWORD)size);
                    pt += n; sizeS -= n;
                 
                    n = SimpleRs::addr2asc(pt, sizeS, " caller=0x", caller);
                     ::OutputDebugStringA(typebuff);
                   }
                  }
                  else {++uiCounto;}
                 }
                 LeaveCriticalSection(&CrSeo);
                 return p;
                }
                // ---------------------------------------------------------------------------------
                // Обработчик delete.
                void delroutineo(PVOID caller,void* p)
                {
                 EnterCriticalSection(&CrSeo);
                 
                 if(p)
                 {
                  if(!killAddro(p))
                  {
                   if(++uiCountDel <= MESS_RESEARCH_NEW)
                   {
                    char* pt     = typebuff;
                    size_t sizeS = ARRAYSIZE(typebuff);
                    size_t n     = 0;
                 
                    n = SimpleRs::str2str (pt, sizeS, "*********************************"," Delete addr error");
                    pt += n; sizeS -= n;
                 
                    n = SimpleRs::addr2asc(pt, sizeS, " p=0x", p);
                    pt += n; sizeS -= n;
                 
                    n = SimpleRs::addr2asc(pt, sizeS, " caller=0x", caller);
                    ::OutputDebugStringA(typebuff);
                   }
                  }
                  else
                  {
                   --uiCounto;
                  }
                 
                  bool btype=false;
                  if(!keyotype) { btype = sizeAddro()==LCOUNT_RESEARCH_NEW; }
                  else          { btype = sizeAddro()<=LCOUNT_RESEARCH_NEW; }
                  if(btype)
                  {
                   SimpleRs::dword2dec (typebuff, ARRAYSIZE(typebuff), "----- ErrorsCount=", uiCounto);
                   ::OutputDebugStringA(typebuff);
                   typeAddrso();
                  }
                 
                  if(sizeAddro()==0)
                  {
                   ::OutputDebugStringA("----- new-delete errors not found -----");
                   ::OutputDebugStringA(" ");
                  }
                 
                  free(p);
                 }
                 
                 LeaveCriticalSection(&CrSeo);
                }
                // ---------------------------------------------------------------------------------
                #pragma warning (push)
                #pragma warning (disable:4700)
                #pragma optimize ("", off)
                // ---------------------------------------------------------------------------------
                // Перегрузка операции new.
                inline void* __cdecl operator new(size_t size)
                {
                 volatile PVOID caller = (PVOID)(&caller)[RET_ADDR_STACK_OFFSET];
                 return newroutineo(caller,size);
                }
                // ---------------------------------------------------------------------------------
                // Перегрузка операции delete.
                inline void __cdecl operator delete(void *p)
                {
                 volatile PVOID caller = (PVOID)(&caller)[RET_ADDR_STACK_OFFSET];
                 delroutineo(caller,p);
                }
                // ---------------------------------------------------------------------------------
                #pragma optimize ("", on)
                #pragma warning (pop)
                // ---------------------------------------------------------------------------------
                 
                 
                #endif

              Сообщение отредактировано: ЫукпШ -
              Подпись была выключена в связи с наложенным заземлением.
              1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
              0 пользователей:


              Рейтинг@Mail.ru
              [ Script Execution time: 0,1402 ]   [ 14 queries used ]   [ Generated: 27.05.20, 21:57 GMT ]