Different behavior of CString "+ =" and "+" statements

When porting an application from VisualStudio 2005 to VisualStudio 2015, we found different behavior in some code that combines CString instances when this code is built with VS2015.
So, I created a simple Win32 console application to demonstrate the problem.

The console application (using MFC as a common dll and Unicode character set) performs this simple function:

void f() { CString x( '\0' ); CString r( 'a' ); r += x; CString rr( 'a' ); rr = rr + x; int rSize = r.GetLength(); int rrSize = rr.GetLength(); assert( rSize == rrSize ); // This assert fires when compiled and run // under Visual Studio 2015! } 

This shows that when a CString containing a '\ 0' char concatenates with another CString instance, using '+ =' or using '+' produces different results!

When using "+ =", the size of the result is calculated, counting all the characters up to the first "\ 0" ... so the final size is 1!
Conversely, when the + operator is used, the result of the CString is 2, that is, the sum of the sizes of the concatenated instances!

In VisualStudio 2005, the size of the result is always the sum of the sizes of the concatenated instances!

I filed a bug at Microsoft a few weeks ago, but so far I have no answer from these guys.

My questions:
1. Have someone stumble upon this error in the MCF library?
2. How did you work on this error? We are thinking of prohibiting the use of the + = operator or replacing the CString class with our own class, but all this seems to me to be "slightly" invasive.

+6
source share
1 answer

The documentation for the CStringT Class contains the following cryptographic instruction:

Although it is possible to create instances of CStringT containing embedded null characters, we recommend against it. Call methods and statements on CStringT objects that contain embedded null characters can produce unintended results.

Honestly, I really don't know what to do with the final offer. I take this as a warning to be careful when nulling characters. Regardless, contractual warranties must still be respected.

Analysis:

This does not seem to apply to CStringT :: operator + = . In the question code example, the implementation of operator+= calls

 CSimpleStringT& operator+=( const CSimpleStringT& strSrc ) 

overload, which changes the current instance, causing

 void Append( const CSimpleStringT& strSrc ) 

which in turn causes

 void Append( PCXSTR pszSrc, int nLength ) 

passes an argument with an explicit length. This is enough to work with C-style strings with embedded null characters. Oddly enough, the implementation then begins to guess the input by calling StringLengthN(pszSrc, nLength) (implemented as a wcsnlen call) to recalculate the length of pszSrc. This returns 0 for the instance CStringT instance x in the sample code.

Result:

It seems to me that this is a mistake in implementation. By the way, if you cancel the arguments with operator+= (i.e. x += r; vs. r += x; ), the result will be a string with a length of 2, as expected.

Resolution:

The only clean solution is to get Microsoft to acknowledge the error and provide a fix. However, I would not hold my breath, because Microsoft usually does not send bug fixes if they change the behavior of the shipped product.

If you cannot convince Microsoft to fix this error, your only option is to not use an operator with unwanted behavior. One way is to use another class of strings. A well-established replacement for std :: wstring , which you can convert to CStringW if necessary ( CStringW cstr(s.c_str(), s.length()); ).

<h / "> Update (2016-09-13):

The OP filed with Microsoft with Microsoft, and they confirmed the error. A bug fix has been fixed, but "it will not be displayed until the next major version of libraries (which may not necessarily be sent in the current [2016-03-31] Visual Studio vNext)."

+6
source

All Articles