Board index » cppbuilder » stl code guard

stl code guard


2006-02-01 01:29:51 AM
cppbuilder22
Hi.
I keep getting a code guard error.
I'm using borland 5.02 on an XP pro machine.
I've patched the Borland rtl with no improvement.
it complains about this line below: finish = tmp + size() + 1;
which is in bc5\include\vector.h. (see way below)
Now it does not happen all the time, (the actual code being executed
is executed maybe 12 times, but it only happens twice).
1 - I have not seen anything about an stl bug like this... has anyone
else?
2 - the actual code is a bit unusual...
basically a dll written in another ide (cbuilder) has a pointer to a
static function in an owl class.
When the user clicks on the form, the handler function calls the
static function which calls a third inside the class non static, which
calls a fourth function is in a dll written in borland c++ 5.02.
This third function is iterating through some databse rows and adding
to an stl vector, some objects... it is the "push_back" which is
causing the code guard complaint 2 times out of, maybe 12.
while (cmd.FetchNext())
{
AITStringPair theData;
theData.strFirst = (const char*) cmd.Field("doc_name").asString();
theData.strSecond = (const char*) cmd.Field("label").asString();
vGotoHotspots.push_back(theData);
nDbRetStat = DB_OKAY;
}
the AITStringPair code is at the bottom...
any ideas on how I can figure this out?
thanks
template <class T>
void vector<T>::insert_aux (iterator position, const T& x)
{
if (finish != end_of_storage)
{
construct(finish, *(finish - 1));
copy_backward(position, finish - 1, finish);
*position = x;
++finish;
}
else
{
//
// We always allocate enough space for a number of additional
// elements in the vector, unless the size of each element is
// very large.
//
const size_type CHUNKSIZE = sizeof(T)>= 1024 ? 1 : 1024 /
sizeof(T);
size_type len = size() ? 2 * size() : CHUNKSIZE;
iterator tmp = the_allocator.allocate(len);
uninitialized_copy(begin(), position, tmp);
construct((tmp + (position - begin())), x);
uninitialized_copy(position, end(), tmp + (position - begin())
+ 1);
destroy(begin(), end());
the_allocator.deallocate(begin());
end_of_storage = tmp + len;
finish = tmp + size() + 1;
start = tmp;
}
}
The code guard log says:
Error 00069. 0x104030 (Thread 0x0BE8):
Pointer in freed memory: 0x0252D1F4-0x0252D1F4.
| C:\BC5\INCLUDE\vector.h line 429:
| the_allocator.deallocate(begin());
| end_of_storage = tmp + len;
|>finish = tmp + size() + 1;
| start = tmp;
| }
Call Tree:
0x00A5CA44(=aitdbi.dll:0x01:00BA44) C:\BC5\INCLUDE\vector.h#429
0x00C70EDD(=aitdbi.dll:0x01:21FEDD) docannotinfo.cpp#85
0x0040EBFC(=SHELL32.dll:0x03:1F4BFC)
0x0040FEA2(=SHELL32.dll:0x03:1F5EA2)
0x01A841AC(=AnnotSpreadsheetBOM.dll:0x01:0031AC)
Z:\DLLS\AnnotSpreadsheetBom\SpreadSheetBOMDialog.cpp#596
0x01A83DC5(=AnnotSpreadsheetBOM.dll:0x01:002DC5)
Z:\DLLS\AnnotSpreadsheetBom\SpreadSheetBOMDialog.cpp#554
The object (0x0252D1F4) [size: 0 bytes] was created with new
Call Tree:
0x0040FE00(=SHELL32.dll:0x03:1F5E00)
0x01A841AC(=AnnotSpreadsheetBOM.dll:0x01:0031AC)
Z:\DLLS\AnnotSpreadsheetBom\SpreadSheetBOMDialog.cpp#596
0x01A83DC5(=AnnotSpreadsheetBOM.dll:0x01:002DC5)
Z:\DLLS\AnnotSpreadsheetBom\SpreadSheetBOMDialog.cpp#554
0x01AEB2F6(=AnnotSpreadsheetBOM.dll:0x01:06A2F6)
0x01AEE148(=AnnotSpreadsheetBOM.dll:0x01:06D148)
0x01AEE280(=AnnotSpreadsheetBOM.dll:0x01:06D280)
============header
#include <owl\owlpch.h>
#include <vector>
#include <list>
using namespace std;
class AITStringPair
{
public:
string strFirst;
string strSecond;
AITStringPair();
AITStringPair(const AITStringPair&);
~AITStringPair();
int operator==(const AITStringPair&) const;
int operator<(const AITStringPair&) const;
};
============cpp
AITStringPair::AITStringPair()
{
}
AITStringPair::AITStringPair(const AITStringPair& dup)
{
strFirst = dup.strFirst;
strSecond = dup.strSecond;
}
AITStringPair::~AITStringPair()
{
}
int AITStringPair::operator==(const AITStringPair& inVal) const
{
return ((inVal.strFirst == strFirst)&&
(inVal.strSecond == strSecond));
}
int AITStringPair::operator<(const AITStringPair& inVal) const
{
return ((inVal.strFirst < strFirst) ||
((inVal.strFirst == strFirst)&&(inVal.strSecond <
strSecond)));
}
Jeff Kish
 
 

Re:stl code guard

Jeff Kish < XXXX@XXXXX.COM >writes:
Quote
I keep getting a code guard error.
I'm using borland 5.02 on an XP pro machine.

I've patched the Borland rtl with no improvement.

it complains about this line below: finish = tmp + size() + 1;
which is in bc5\include\vector.h. (see way below)

Now it does not happen all the time, (the actual code being executed
is executed maybe 12 times, but it only happens twice).

1 - I have not seen anything about an stl bug like this... has anyone
else?
I'm doing a little bit of forensics here; I don't have the Borland
C++'s vector implementation around any more.
Quote
template <class T>
void vector<T>::insert_aux (iterator position, const T& x)
{
if (finish != end_of_storage)
{
construct(finish, *(finish - 1));
copy_backward(position, finish - 1, finish);
*position = x;
++finish;
}
else
{
//
// We always allocate enough space for a number of additional
// elements in the vector, unless the size of each element is
// very large.
//
const size_type CHUNKSIZE = sizeof(T)>= 1024 ? 1 : 1024 /
sizeof(T);
size_type len = size() ? 2 * size() : CHUNKSIZE;
iterator tmp = the_allocator.allocate(len);
uninitialized_copy(begin(), position, tmp);
construct((tmp + (position - begin())), x);
uninitialized_copy(position, end(), tmp + (position - begin())
+ 1);
destroy(begin(), end());
the_allocator.deallocate(begin());
end_of_storage = tmp + len;
finish = tmp + size() + 1;
start = tmp;
}
}
There seem to be the following invariants:
* end_of_storage points one position past the end of the memory
allocated for holding the vector elements
* start points at the first element
* finish points one position past the last vector element
When the memory allocated so far is exhausted because of the insertion
of another element,
1. tmp points at the newly allocated chunk of memory
2. The elements of the range starting at begin() and ending at (but
not including) position are copied to the beginning of the new chunk
of memory
3. A copy of x is constructed into the memory residing directly after
the elements copied in step 2
4. The remaining elments are copied from the original chunk to the new
chunk, starting at the position directly after the element constructed
in step 2
5. The elements in the old chunk are destructed
6. The old chunk is deallocated
7. The invariants mentioned above are established again; thereby
size() is computed based on values of start and finish that point to
deallocated memory. This assumption is based on the guess that size()
returns finish-start; is that correct?
If my assumption is correct, CodeGuard is right - the code has
undefined behavior. Move the line the_allocator.deallocate(begin());
between the lines containing the assignments to finish and start, and
CodeGuard should be happy again.
 

Re:stl code guard

On Tue, 31 Jan 2006 19:56:03 +0100, XXXX@XXXXX.COM (Thomas Maeder
[TeamB]) wrote:
Quote
Jeff Kish < XXXX@XXXXX.COM >writes:

>I keep getting a code guard error.
>I'm using borland 5.02 on an XP pro machine.
>
>I've patched the Borland rtl with no improvement.
>
>it complains about this line below: finish = tmp + size() + 1;
>which is in bc5\include\vector.h. (see way below)
>
>Now it does not happen all the time, (the actual code being executed
>is executed maybe 12 times, but it only happens twice).
>
>1 - I have not seen anything about an stl bug like this... has anyone
>else?

I'm doing a little bit of forensics here; I don't have the Borland
C++'s vector implementation around any more.


>template <class T>
>void vector<T>::insert_aux (iterator position, const T& x)
>{
>if (finish != end_of_storage)
>{
>construct(finish, *(finish - 1));
>copy_backward(position, finish - 1, finish);
>*position = x;
>++finish;
>}
>else
>{
>//
>// We always allocate enough space for a number of additional
>// elements in the vector, unless the size of each element is
>// very large.
>//
>const size_type CHUNKSIZE = sizeof(T)>= 1024 ? 1 : 1024 /
>sizeof(T);
>size_type len = size() ? 2 * size() : CHUNKSIZE;
>iterator tmp = the_allocator.allocate(len);
>uninitialized_copy(begin(), position, tmp);
>construct((tmp + (position - begin())), x);
>uninitialized_copy(position, end(), tmp + (position - begin())
>+ 1);
>destroy(begin(), end());
>the_allocator.deallocate(begin());
>end_of_storage = tmp + len;
>finish = tmp + size() + 1;
>start = tmp;
>}
quite a generous donation of 'forensics'.
Anyone know what I need to do to get this to work, i.e. build anything
in Borland 5.02, or just make the change and rebuild my app?
I'm guessing it is just the app because it is a template and that
stuff should come all from headers during compile.
Quote
>}

There seem to be the following invariants:
* end_of_storage points one position past the end of the memory
allocated for holding the vector elements
* start points at the first element
* finish points one position past the last vector element

When the memory allocated so far is exhausted because of the insertion
of another element,
1. tmp points at the newly allocated chunk of memory
2. The elements of the range starting at begin() and ending at (but
not including) position are copied to the beginning of the new chunk
of memory
3. A copy of x is constructed into the memory residing directly after
the elements copied in step 2
4. The remaining elments are copied from the original chunk to the new
chunk, starting at the position directly after the element constructed
in step 2
5. The elements in the old chunk are destructed
6. The old chunk is deallocated
7. The invariants mentioned above are established again; thereby
size() is computed based on values of start and finish that point to
deallocated memory. This assumption is based on the guess that size()
returns finish-start; is that correct?

If my assumption is correct, CodeGuard is right - the code has
undefined behavior. Move the line the_allocator.deallocate(begin());
between the lines containing the assignments to finish and start, and
CodeGuard should be happy again.
Jeff Kish
 

{smallsort}

Re:stl code guard

<snip>
Quote
I'm doing a little bit of forensics here; I don't have the Borland
C++'s vector implementation around any more.


>template <class T>
>void vector<T>::insert_aux (iterator position, const T& x)
>{
>if (finish != end_of_storage)
>{
>construct(finish, *(finish - 1));
>copy_backward(position, finish - 1, finish);
>*position = x;
>++finish;
>}
>else
>{
>//
>// We always allocate enough space for a number of additional
>// elements in the vector, unless the size of each element is
>// very large.
>//
>const size_type CHUNKSIZE = sizeof(T)>= 1024 ? 1 : 1024 /
>sizeof(T);
>size_type len = size() ? 2 * size() : CHUNKSIZE;
>iterator tmp = the_allocator.allocate(len);
>uninitialized_copy(begin(), position, tmp);
>construct((tmp + (position - begin())), x);
>uninitialized_copy(position, end(), tmp + (position - begin())
>+ 1);
>destroy(begin(), end());
>the_allocator.deallocate(begin());
>end_of_storage = tmp + len;
>finish = tmp + size() + 1;
>start = tmp;
>}
>}

There seem to be the following invariants:
* end_of_storage points one position past the end of the memory
allocated for holding the vector elements
* start points at the first element
* finish points one position past the last vector element

When the memory allocated so far is exhausted because of the insertion
of another element,
1. tmp points at the newly allocated chunk of memory
2. The elements of the range starting at begin() and ending at (but
not including) position are copied to the beginning of the new chunk
of memory
3. A copy of x is constructed into the memory residing directly after
the elements copied in step 2
4. The remaining elments are copied from the original chunk to the new
chunk, starting at the position directly after the element constructed
in step 2
5. The elements in the old chunk are destructed
6. The old chunk is deallocated
7. The invariants mentioned above are established again; thereby
size() is computed based on values of start and finish that point to
deallocated memory. This assumption is based on the guess that size()
returns finish-start; is that correct?
Here are those parts of the header:
size_type size () const { return size_type(end() - begin()); }
iterator begin () { return start; }
iterator end () { return finish; }
It's hard to follow what the template is doing, but I'm guessing you
are correct.
Quote

If my assumption is correct, CodeGuard is right - the code has
undefined behavior. Move the line the_allocator.deallocate(begin());
between the lines containing the assignments to finish and start, and
CodeGuard should be happy again.
So you mean like this?
destroy(begin(), end());
// the_allocator.deallocate(begin());
end_of_storage = tmp + len;
finish = tmp + size() + 1;
the_allocator.deallocate(begin());
start = tmp;
Jeff Kish
 

Re:stl code guard

<snip>
Quote
>If my assumption is correct, CodeGuard is right - the code has
>undefined behavior. Move the line the_allocator.deallocate(begin());
>between the lines containing the assignments to finish and start, and
>CodeGuard should be happy again.
So you mean like this?

destroy(begin(), end());
// the_allocator.deallocate(begin());
end_of_storage = tmp + len;
finish = tmp + size() + 1;
the_allocator.deallocate(begin());
start = tmp;
Jeff Kish
I'm not 100% sure, but I think things are fine / better now. Thanks
Thomas.
Regards
Jeff Kish
 

Re:stl code guard

Jeff Kish < XXXX@XXXXX.COM >writes:
Quote
>If my assumption is correct, CodeGuard is right - the code has
>undefined behavior. Move the line the_allocator.deallocate(begin());
>between the lines containing the assignments to finish and start, and
>CodeGuard should be happy again.

So you mean like this?

destroy(begin(), end());
// the_allocator.deallocate(begin());
end_of_storage = tmp + len;
finish = tmp + size() + 1;
the_allocator.deallocate(begin());
start = tmp;
Yes.
 

Re:stl code guard

Jeff Kish < XXXX@XXXXX.COM >writes:
Quote
Anyone know what I need to do to get this to work, i.e. build anything
in Borland 5.02, or just make the change and rebuild my app?
I'm guessing it is just the app because it is a template and that
stuff should come all from headers during compile.
Changing the relevant header should cause the applications depending
on it to be recompiled. And that should be enough - nothing needs to
be changed in Borland 5.02 (whatever that would mean).