Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CString::GetLength error

466 views
Skip to first unread message

Frank Perry

unread,
Jan 6, 2010, 12:13:02 PM1/6/10
to
Howdy,

I'm having a problem with CString. Rarely but too often, GetLength returns
the wrong length. A recent example is a CString "OR" returned a length of
0xDD000002. As you could guess, this caused Serialize to have a heartattack.

Has anyone seen this kind of problem before and have an idea of the cause
and of a solution?

--
Frank Perry
LavaLeaf Software

David Wilkinson

unread,
Jan 6, 2010, 12:35:25 PM1/6/10
to

If your app is Unicode, I hope you used L"OR" or _T("OR").

--
David Wilkinson
Visual C++ MVP

Tom Serface

unread,
Jan 6, 2010, 1:15:15 PM1/6/10
to
I've never seen this, but you could try tracing down into the GetLength()
function to see what it is looking at. That string looks innocent enough.
Even if you were using Unicode it would have just stored it as ASCII so it
might not have been what you wanted, but it still should have worked.

Tom

"Frank Perry" <Frank...@discussions.microsoft.com> wrote in message
news:D96766AC-B5BE-40D4...@microsoft.com...

Joseph M. Newcomer

unread,
Jan 6, 2010, 2:37:13 PM1/6/10
to
Under normal conditions this is not possible.

You would need to show the code, as a start.

It could also be a memory clobber by the block of memory preceding the CString overwriting
its space and clobbering the data, or a data underrun if you ever unwrap the string
representation. There are a huge number of explanations, but there is insufficient
context to determine which one might apply.

Consider the following questions:
Have you ever done a GetBuffer/ReleaseBuffer on this string?
Have you ever done a GetBuffer/ReleaseBuffer on any string?
Do you have any data structure with a fixed-size array of anything in it?

That's just a start.
joe

On Wed, 6 Jan 2010 09:13:02 -0800, Frank Perry <Frank...@discussions.microsoft.com>
wrote:

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Frank Perry

unread,
Jan 6, 2010, 5:27:01 PM1/6/10
to
Howdy,

I'll try and cover several questions.

The program is not Unicode.

The CString in the case here could be generated one of serveral ways. The
most likey is:
const char *DefOperators[] =
{
"OR",
"AND",
"ADJ",
"NEAR",
"WITH",
"SAME"
};

CString ValidateDefOperator(CString Value)
{
Value.MakeUpper();
int Size = sizeof(DefOperators)/sizeof(DefOperators[0]);
for(int i=0; i<Size; i++)
if(DefOperators[i] == Value)
return Value;
return "OR";
}
When it comes from some other source, it will be processed here so the end
result would be the same.

I can't trace it because it is a rare occurrence. I'm afraid that logic is
about all I can apply to the problem.

I don't see instances of GetBuffer applied to the string in question. The
data is a class variable. If something is clobbering the string, it will be
almost impossible to sort out of the hundreds of C++ files that make up the
code.

One reason for asking about this is I had a similar problem show up when a
CString was being returned from or Oracle ODBC driver. That would sometimes
return a bad length for the string in a field of the rowset. It was returned
from the driver with a problem before anything in the program itself touched
it. I was wondering if this was similar.

The string itself is corrupted because the serialized data for it is FF FF
FF 02 00 00 DD, which indicates it was returned to the serialize string
function as 0xDD000002 bytes long.

--
Frank Perry
LavaLeaf Software

Tom Serface

unread,
Jan 6, 2010, 6:36:09 PM1/6/10
to
I wonder if your getting a referencing problem. CString attempts to not
create new values if it thinks it can use the same one for multiple
occurrences. I've been caught by this before. I usually force the issue by
using the LPCTSTR operator like:

CString cs = (LPCTSTR) csValue;

Might be worth a try anyway.

Tom

"Frank Perry" <Frank...@discussions.microsoft.com> wrote in message

news:4B4C1346-2741-4FB2...@microsoft.com...

Giovanni Dicanio

unread,
Jan 7, 2010, 4:19:12 AM1/7/10
to
"Tom Serface" <t...@camaswood.com> ha scritto nel messaggio
news:OWdPGkyj...@TK2MSFTNGP05.phx.gbl...

> I wonder if your getting a referencing problem. CString attempts to not
> create new values if it thinks it can use the same one for multiple
> occurrences.

I think CString is a very robust class.

I would think that string corruption originated in some other places in OP's
code (maybe some buffer overrun).

Giovanni

Goran

unread,
Jan 7, 2010, 4:37:09 AM1/7/10
to
On Jan 6, 11:27 pm, Frank Perry <FrankPe...@discussions.microsoft.com>
wrote:

> The string itself is corrupted because the serialized data for it is FF FF
> FF 02 00 00 DD, which indicates it was returned to the serialize string
> function as 0xDD000002 bytes long.

So it's not a GetLength error, but serialization error. OK, I'll put
my serialization master hat on now...

What I can say is: your file is borked and there's nothing you can do
about that. Best approach by far is to find the source of the problem,
and that will be inspection of the "save" path for said files.

At load time, when you get bad data, you are already dead.
Serialization is, in principle, an all-or-nothing proposition, so
attempts to salvage stuff at load time are __very difficult__, and, in
general case, doomed to fail.

Goran.

Anthony Wieser

unread,
Jan 7, 2010, 6:35:27 AM1/7/10
to
It may of course be the deserialization code of some object somewhere before
it in the stream that's at fault instead.

Anthony Wieser
Wieser Software Ltd


"Goran" <goran...@gmail.com> wrote in message
news:a9de3f6a-20f5-49bf...@m26g2000yqb.googlegroups.com...

Frank Perry

unread,
Jan 7, 2010, 10:09:01 AM1/7/10
to
Howdy,

I looked at the serialization code for serializing a CString. It gets the
length from CString and based on that length writes out the length of the
length (if that makes sense) in the form of a mask before adding the string.
From that, I think the GetLength is the problem. Based on the length, it
prefaces the length with either no bytes if the length is 0 - 0xfe, or FF if
it's 0xff to 0xfffe, etc. It prefaces the string length with 0xff 0xff 0xff
so it clearly believes the length is 0xDD000002 (e.i. requiring 4 bytes to
express).

I am not sure what I think about the buffer overrun. On the one hand, it is
an obvious possibility that something else is clobbering the data. But on
the other hand, almost everything we write is a string and 0xDD isn't in the
normal character set. If it was something like 0x41 or 0x20 it would make
much more sense.

I am not familiar with the format of a CString but is the length someplace
where it could be clobbered by an overrun while leaving the actual 2 inplace
and also leave enought of the rest of the header to still function as a
string? Assuming it's 'little endian' I would think the 2 would have been
clobbered before an overwrite would leave an 0xdd three bytes deeper in the
CString header.

I find the idea of a copy function going bad hopeful. (If only because I
can change that quickly and see what happens.) In my experience, copying a
string with a bad length will result in the new string being just as bad as
the old one. It copies by the string's stated length and not the actual
length. (My ODBC Cstring problem was correctable by saving a new string with
LockBuffer which stopped at the first 0x00 and not the GetLength value.)



--
Frank Perry
LavaLeaf Software


"Goran" wrote:

> .
>

Joseph M. Newcomer

unread,
Jan 7, 2010, 10:39:01 AM1/7/10
to
See below...
On Wed, 6 Jan 2010 14:27:01 -0800, Frank Perry <Frank...@discussions.microsoft.com>
wrote:

>Howdy,


>
>I'll try and cover several questions.
>
>The program is not Unicode.
>
>The CString in the case here could be generated one of serveral ways. The
>most likey is:
>const char *DefOperators[] =
>{
> "OR",
> "AND",
> "ADJ",
> "NEAR",
> "WITH",
> "SAME"
>};

****
The above declaration is erroneous. If you are using CString, the only correct format
would have been

LPCTSTR DefOperators[] =
{
_T("OR"),
_T("AND"),
...etc.
};

Otherwise, your code will not be correct if it is compiled as Unicode. It is extremely
important to realize that in 2010, the data type 'char' should be considered obsolete
except in very rare and exotic circumstances, and not only is this not one, but you have
asserted that CString must necessarily be 8 bit characters, which is simply not true.
****


>
>CString ValidateDefOperator(CString Value)
>{
> Value.MakeUpper();
> int Size = sizeof(DefOperators)/sizeof(DefOperators[0]);

****
Starting in VS2008, the poorly-documented _countof could be used:
int Size = _countof(DefOperators);
It is not clear why you have to introduce a separate variable for this, since the
expression is a compile time constant and takes no runtime cost to evaluate.
****


> for(int i=0; i<Size; i++)
> if(DefOperators[i] == Value)
> return Value;
> return "OR";

****
return _T("OR");
****


>}
>When it comes from some other source, it will be processed here so the end
>result would be the same.
>
>I can't trace it because it is a rare occurrence. I'm afraid that logic is
>about all I can apply to the problem.

****
The "rare occurrence" part suggests memory damage. See my essay on memory damage
detection on my MVP Tips site.
****


>
>I don't see instances of GetBuffer applied to the string in question. The
>data is a class variable. If something is clobbering the string, it will be
>almost impossible to sort out of the hundreds of C++ files that make up the
>code.

****
Note that I also asked "Did you every use GetBuffer/ReleaseBuffer on *any* string?"
(emphasis added).

It looks like a data overrun problem, but it could also be an uninitialized-pointer
problem. But an uninitialized-pointer problem should show up in debug mode as an access
fault to some weird-looking address.
****


>
>One reason for asking about this is I had a similar problem show up when a
>CString was being returned from or Oracle ODBC driver. That would sometimes
>return a bad length for the string in a field of the rowset. It was returned
>from the driver with a problem before anything in the program itself touched
>it. I was wondering if this was similar.
>
>The string itself is corrupted because the serialized data for it is FF FF
>FF 02 00 00 DD, which indicates it was returned to the serialize string
>function as 0xDD000002 bytes long.

****
Not sure what the FF FF FF represents. I don't use MFC serialization because I consider
it deeply unreliable in the presence of schema evolution. But it still looks like memory
damage, unless there is perhaps a bad serialization call that has set the serialization
stream off-by-one, or something else weird.
joe
****

Joseph M. Newcomer

unread,
Jan 7, 2010, 10:57:25 AM1/7/10
to
0xDD is the byte used to represent free storage in the debug heap (see crt\src\dbgheap.c
in the VC directory, for example). So if one of these bytes were copied accidentally into
the space, for example, by using a dead pointer, who knows what is going to happen? If a
pointer which used to point to a structure is used to obtain a byte, you might get 0xDD,
and if another pointer to what used to point to another structure is used to store it, and
that pointer now points to what is now a CString, well, that's certain death, and the data
you see could result. Note that sometimes the data might be a 0 in which case a 0
overwrites a 0, so the bug only shows up when the overwritten data is nonzero.

Try running under the Application Verifier with all possible storage tests turned on. It
might show up something.
joe

On Thu, 7 Jan 2010 07:09:01 -0800, Frank Perry <Frank...@discussions.microsoft.com>
wrote:

>Howdy,

Frank Perry

unread,
Jan 11, 2010, 1:09:01 PM1/11/10
to
Howdy,

I haven't been able to use Application Verify. It seems to block my access
to the database. I haven't had a chance to see why or how but when I have my
program listed in it, the program failes to return data from the ACE dll that
interacts with the database.

--
Frank Perry
LavaLeaf Software


"Joseph M. Newcomer" wrote:

> .
>

Joseph M. Newcomer

unread,
Jan 11, 2010, 4:53:09 PM1/11/10
to
Hmmm...that's interesting, and may already be symptomatic of a problem. I've not used
databases, so don't know about potential problems that might exist.
joe

On Mon, 11 Jan 2010 10:09:01 -0800, Frank Perry <Frank...@discussions.microsoft.com>
wrote:

>Howdy,
>


>I haven't been able to use Application Verify. It seems to block my access
>to the database. I haven't had a chance to see why or how but when I have my
>program listed in it, the program failes to return data from the ACE dll that
>interacts with the database.

Hector Santos

unread,
Jan 12, 2010, 1:08:48 AM1/12/10
to
Frank Perry wrote:

> ....


> I can't trace it because it is a rare occurrence. I'm afraid that logic is
> about all I can apply to the problem.


In general when rare and intermittent things like this rear its head,
it means its a PDE - programming design error.

It could be buffer overflow, underflow or whatever, a corruption is
occurring somewhere. This basically means, you need to isolate your
code, black box it and make sure its perfect in isolated testing and
if you still have problems when you plug it back into your
application, then you have a PE somewhere. Its that plain and simple. :)

Divide and conquer is one way to get to this problems. A good heap
manager tool may help too.

Happy Hunting!

--
HLS

Tom Serface

unread,
Jan 12, 2010, 12:12:06 PM1/12/10
to

Hi Frank,

You could try switching out to a std:string instead and see if you get a
similar issue. That may not be an easy thing to do, but it would prove
whether it's CString's fault or the fault of something in your code. I use
CString a LOT with absolutely not problems, but that doesn't prove that
there are none. As I mentioned before I do use a specific cast (LPCTSTR) on
occasion to force CString to create a new copy since I've found the
reference counter to have problems on occasion, but other than that it works
as advertised. If you could switch out to a different kind of string and
you still have the issue then ...

Tom

"Frank Perry" <Frank...@discussions.microsoft.com> wrote in message

news:3982A5BD-AA09-4B89...@microsoft.com...

Frank Perry

unread,
Jan 12, 2010, 5:07:01 PM1/12/10
to
Howdy,

I wish I could create test versions but that isn't in the cards. There are
about 6000 people who use the program. It's a government contract and we are
not allowed by contract to install anything that isn't run through the full
FQT process and pushed to all the workstations at once. The problem is rare
so ofcourse it never happens on my test machine.


--
Frank Perry
LavaLeaf Software


"Hector Santos" wrote:

> .
>

Tom Serface

unread,
Jan 12, 2010, 5:19:33 PM1/12/10
to
Man, I can say, been there done that... I don't know how to solve the
problem, but I can commiserate.

Tom

"Frank Perry" <Frank...@discussions.microsoft.com> wrote in message

news:B62D058D-F26A-4168...@microsoft.com...

Frank Perry

unread,
Jan 12, 2010, 5:45:01 PM1/12/10
to
Howdy,

I wouldn't be surprised that there is a problem with the DLL we use to
access the database. (That has to be taken with a grain of salt as the DLL
isn't _our_ DLL and would be someone else's problem, so I'm biased.)

I will continue to try and get Application Verify to run. But, the cycle of
juggling priorities is moving away from this problem, so it may be a few days
before I get it worked out.

--
Frank Perry
LavaLeaf Software


"Joseph M. Newcomer" wrote:

> .
>

0 new messages