Click here to Skip to main content
Click here to Skip to main content

BUG: MFC 7.0's CByteArray::Serialize() reads too much data

By , 10 Jun 2002
Rate this:
Please Sign up or sign in to vote.
<!-- Add the rest of your HTML here -->

Introduction

In the recently-released version of Visual Studio.NET, there is a bug in MFC's new implementation of CByteArray::Serialize(). The function has been enhanced from the previous version so that it can read more than INT_MAX bytes. This is great, but apparently a line of code was mistakenly copied and pasted in the portion of the code that loads archives. The result is that CByteArray::Serialize() reads twice as much data from the archive as it's supposed to.

This article shows one way to work around the problem until Microsoft can correct it. I've searched the Knowledge Base and found no mention of it, so I hope Microsoft is aware of the problem.

Current Implementation

This is the current (buggy) implementation of CByteArray::Serialize from MFC's array_b.cpp. In the source below, note the extra ar.Read(pbData, nBytesToRead) statement in bold.

void CByteArray::Serialize(CArchive& ar)
{
	UINT_PTR nBytesLeft;
	UINT nBytesToWrite;
	UINT nBytesToRead;
	LPBYTE pbData;

	ASSERT_VALID(this);

	CObject::Serialize(ar);

	if (ar.IsStoring())
	{
		ar.WriteCount(m_nSize);
		nBytesLeft = m_nSize*sizeof(BYTE);
		pbData = m_pData;
		while(nBytesLeft > 0)
		{
			nBytesToWrite = UINT(min(nBytesLeft, INT_MAX));
			ar.Write(pbData, nBytesToWrite);
			pbData += nBytesToWrite;
			nBytesLeft -= nBytesToWrite;
		}
	}
	else
	{
		DWORD_PTR nOldSize = ar.ReadCount();
		SetSize(nOldSize);
		nBytesLeft = m_nSize*sizeof(BYTE);
		pbData = m_pData;
		while(nBytesLeft > 0)
		{
			nBytesToRead = UINT(min(nBytesLeft, INT_MAX));
			ar.Read(pbData, nBytesToRead);
			pbData += nBytesToRead;
			nBytesLeft -= nBytesToRead;
			ar.Read(pbData, nBytesToRead);
		}
	}
}

Effects

This has disastrous effects on any application that reads a CByteArray from an archive. In my case, I upgraded my Alarm++ software from VC++ 6.0 to VC++.NET and found the application was crashing in very unusual places. I tracked it down to getting bogus data from an archive, but the real culprit was an earlier CByteArray.Serialize() call that read too far into the archive and caused all the remaining objects to be garbage.

Workaround

One solution is to delete that line and rebuild the MFC libraries. I'm a bit leery of that solution because who knows what else might be introduced by changing the released MFC libraries. Plus, it would introduce the whole issue of shipping your own version of the MFC DLLs (if you use them, which I don't, so maybe I'll consider this solution later).

For the moment, I prefer to fix it in my own code, wait for a service release to fix it, and then take it out. Fortunately, Serialize() is virtual so we can derive our own class from CByteArray and use it instead. Of course, CByteArray is used internally in MFC, so the problem may turn up in other places as well (another reason to re-compile the MFC libraries).

class MyCByteArray : public CByteArray 
{
public:
	MyCByteArray() {}
	virtual ~MyCByteArray() {}

	virtual void Serialize(CArchive& ar)
	{
		UINT_PTR nBytesLeft;
		UINT nBytesToRead;
		LPBYTE pbData;

		ASSERT_VALID(this);

		CObject::Serialize(ar);

		if (ar.IsStoring())
		{
			// We can just call the base implementation here.
			CByteArray::Serialize(ar);
		}
		else
		{
			DWORD_PTR nOldSize = ar.ReadCount();
			SetSize(nOldSize);
			nBytesLeft = m_nSize*sizeof(BYTE);
			pbData = m_pData;
			while(nBytesLeft > 0)
			{
				nBytesToRead = UINT(min(nBytesLeft, INT_MAX));
				ar.Read(pbData, nBytesToRead);
				pbData += nBytesToRead;
				nBytesLeft -= nBytesToRead;
				//BUG: ar.Read(pbData, nBytesToRead);
			}
		}
	}
};

Example

I didn't think this was worth posting a whole sample project for, but here's a small code snippet to show you that it can be used the same way as CByteArry.

      // create a byte array
      MyCByteArray bytes;
      for (int i = 0; i < 5; ++i)
         bytes.Add(i);

      // write out the byte array
      CFile f("test.ar", CFile::modeCreate | CFile::typeBinary | CFile::modeWrite);
      CArchive arStore(&f, CArchive::store);
      bytes.Serialize(arStore);
      arStore.Close();
      f.Close();

      bytes.RemoveAll();   // clear the array

      // read the array back
      f.Open("test.ar", CFile::typeBinary | CFile::modeRead);
      CArchive arLoad(&f, CArchive::load);
      bytes.Serialize(arLoad);

      // display it
      for (int i = 0; i < bytes.GetSize(); ++i)
         cout << "Byte[" << i << "] = " << hex << (int) bytes[i] << dec << endl;

Conclusion

If your code serializes CByteArray objects, you should be aware of this problem in Visual Studio.NET MFC 7.0's implementation of CByteArray::Serialize().

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

skst
Software Developer (Senior)
United States United States
Stefan Tucker has been programming since 1976 (but he's not as old as that implies) in many environments, including: Apple ][, HP2000, IBM 4341, DEC Vax, Apollo Domain, DG AOS/VS, DG/UX, MS-DOS, OS/2, and MS Windows 2.0 to Vista. Languages include BASIC (of course), Fortran, Pascal, PL/1, C, C++, JavaScript, Perl, PHP, PowerShell, Java, C#/.NET, and WPF. Stefan graduated from Brown University in 1985 and is currently living and working and raising two boys in the Chicago area. He'd like to own a cat but has a guinea pig.

Comments and Discussions

 
GeneralFixed in Visual Studio.Net 2003 PinsussAnonymous6-Feb-04 7:20 
GeneralRe: Fixed in Visual Studio.Net 2003 Pinmemberskst6-Feb-04 8:34 
GeneralYou may want to change the title of the article PinmemberAlexpro11-Jun-02 21:55 
GeneralRe: You may want to change the title of the article Pinmemberskst12-Jun-02 3:01 
GeneralIMPLEMENT_SERIAL PinmemberJon Polpetta11-Jun-02 7:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140415.2 | Last Updated 11 Jun 2002
Article Copyright 2002 by skst
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid