Bds 2006 C conflicts with hidden memory manager (class new / delete [] vs. AnsiString)

I have been using BDS 2006 Turbo C ++ for a long time, and some of my large projects ( CAD / CAM, 3D gfx engines and astronomical calculations) sometimes throw an exception (for example, once every 3-12 months 24/7 use in severe conditions). After extensive debugging, I found this:

//code1: struct _s { int i; } // any struct _s *s=new _s[1024]; // dynamic allocation delete[] s; // free up memory 

this code is usually inside the template, where _s can also be a class, so delete[] this code should work correctly, but delete[] does not work properly for structs (classes look OK). No exceptions are thrown, the memory is freed, but it somehow corrupts the distribution tables of the memory manager, and after that any new allocation may be incorrect (new ones may create overlapping allocations with already allocated space or even unallocated space, therefore, random exceptions)

I found that if I add an empty destructor to _s , than everything seems OK

 struct _s { int i; ~_s(){}; } 

Well, now comes the weird part. After I updated this in my projects, I found that the AnsiString class also has poor redistributions. For example:

 //code2: int i; _s *dat=new _s[1024]; AnsiString txt=""; // setting of dat for (i=0;i<1024;i++) txt+="bla bla bla\r\n"; // usage of dat delete[] dat; 

This dat code contains some useful data, and then some txt line created by adding lines, so txt needs to be redistributed several times, and sometimes dat data is overwritten by txt (even if they don't overlap, I suppose the temp AnsiString needed to redistribute txt , overlaps with dat )

So my questions are:

  • Am I doing something wrong in code1, code2?
  • Is there a way to avoid AnsiString (re) placement errors? (but still using it)

    • After extensive debugging (after posting question 2), I found that AnsiString not causing problems. They arise only when they are used. The real problem is probably switching between OpenGL clients. I have Open / Save dialogs with vector graphics preview. If I disable the use of OpenGL for these VCL subframes than AnsiString , the memory management errors will completely disappear. I don’t know what the problem is (incompatibility between the MFC / VCL windows or, most likely, I made a mistake when switching contexts, I will continue to research). OpenGL Context:
    • main VCL Form + OpenGL inside the Canvas client area
    • child of the main MFC Open / Save dialog + attached preview VCL Form + OpenGL inside Canvas client area

PS

  • these errors depend on the number of new/delete/delete[] non-allocated uses
  • errors code1 and code2 are repeated (for example, the parser loads a complex ini file, and the error occurs on the same line if ini does not change)
  • I find these errors only for large projects (simple source code> 1 MB) with a combined use of AnsiString and templates with internal dynamic allocations, but it is possible that they are also in simpler projects, but are so rare that I miss.
  • Infected projects:
    • win32 noinstall standalone (using Win7sp1 x64 , but on XPsp3 x32 it behaves the same)
    • not taken into account when using GDI or OpenGl / GLSL
    • does not measure if device DLL s driver is used or not
    • no OCX or custom VCL component
    • no DirectX
    • 1 byte of aligned compilation / link
    • do not use RTL , packages, or frameworks (stand-alone)

Sorry for the poor English / grammar ... any help / conclusion / suggestion appreciated.

+2
memory-management struct ansistring c ++ builder
source share
1 answer

After extensive debugging, I completely isolated the problem. Memory Management bds2006 Turbo C ++ became corrupted after you tried to cause any deletion for an already deleted pointer. eg:

 BYTE *dat=new BYTE[10],*tmp=dat; delete[] dat; delete[] tmp; 

After that, memory management is not reliable. ("new" can allocate already allocated space)

Of course, deleting the same pointer twice is a mistake on the side of programmers, but I found the true cause of all my problems that cause this problem (without any obvious error in the source code) see this code:

 //--------------------------------------------------------------------------- class test { public: int siz; BYTE *dat; test() { siz=10; dat=new BYTE[siz]; } ~test() { delete[] dat; // <- add breakpoint here siz=0; dat=NULL; } test& operator = (const test& x) { int i; for (i=0;i<siz;i++) if (i<x.siz) dat[i]=x.dat[i]; for ( ;i<siz;i++) dat[i]=0; return *this; } }; //--------------------------------------------------------------------------- test get() { test a; return a; // here call a.~test(); } // here second call a.~test(); //--------------------------------------------------------------------------- void main() { get(); } //--------------------------------------------------------------------------- 

The get() function is called the destructor for the class a twice. Once for a real a and once for a copy of it, because I forgot to create a constructor

 test::test(test &x); 

[Edit1] further code update

OK. I refined the initialization code for both class templates and structure, even to correct even more errors. Add this code to any struct / class / template template and add functionality if necessary

 T() {} T(T& a) { *this=a; } ~T() {} T* operator = (const T *a) { *this=*a; return this; } //T* operator = (const T &a) { ...copy... return this; } 
  • T is the name of the structure / class
  • the last operator is needed only if T uses dynamic distributions inside it, if no distributions are used, you can leave it as

This also fixes other problems with the compiler:

  • Too many initializer errors for a simple array in bcc32

If anyone has similar problems, hope this helps.

Also see pointer tracing in C ++ mmap code if you need to debug memory allocation ...

+2
source share

All Articles