Solved

Error in string handling in func calls after move from VS2003 to VS2005

Posted on 2006-06-17
13
535 Views
Last Modified: 2013-11-20
Hi!

I get an error in my application after moving from VS2003 to VS2005. The application is written in C++/MFC and uses _T("a string") constructions often, as I build it for unicode (but it was originally ASCII only). (It worked in VS2003 btw).

My problem is that I get exceptions rather frequently, and they seem to occur when calling functions like this:
MyFunc(_T("a string"));

where MyFunc is declared as:
void MyFunc(CString parameter)
(happens both when MyFunc is from the same dll and from others, but it is from the same solution I'm building now)

I get an exception deep down in ntdll, and it all seems to come from deep down in the CString construction and the last thing I see in the source code is a call to HeapAlloc.

The Exception is:
First-chance exception at 0x7c81d216 in MyApp.exe: 0xC0000005: Access violation reading location 0xfdfdfdfd

And the call stack is (part of it. All funcs which start with Mz is my code):
       ntdll.dll!7c81d216()       
       [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]      
       ntdll.dll!7c8762e1()       
       ntdll.dll!7c876168()       
       ntdll.dll!7c860201()       
       ntdll.dll!7c81d40c()       
       ntdll.dll!7c81d4a5()       
       ntdll.dll!7c834298()       
       gdi32.dll!77c081c5()       
       kernel32.dll!77e44639()       
       ntdll.dll!7c875e7b()       
       msado15.dll!4bbf6e2a()       
       msado15.dll!4bbf6d66()       
       msado15.dll!4bbf6d70()       
       ntdll.dll!7c85fc22()       
       ntdll.dll!7c87612d()       
       ntdll.dll!7c875dc3()       
       ntdll.dll!7c875dc3()       
       ntdll.dll!7c85fc22()       
       ntdll.dll!7c81d4a5()       
       ntdll.dll!7c85fb00()       
       ntdll.dll!7c81d6bb()       
       ntdll.dll!7c81d742()       
       user32.dll!7739c498()       
       user32.dll!7739c4c8()       
       ntdll.dll!7c81d6bb()       
       ntdll.dll!7c81d742()       
       ntdll.dll!7c81d4a5()       
       ntdll.dll!7c81d4df()       
       ntdll.dll!7c81d4df()       
       ntdll.dll!7c81d742()       
       ntdll.dll!7c87555c()       
       ntdll.dll!7c876951()       
       ntdll.dll!7c8766be()       
       oledb32.dll!4c8725bb()       
       msadce.dll!4d142e80()       
       ntdll.dll!7c8766be()       
       ntdll.dll!7c860386()       
       ntdll.dll!7c81d742()       
       msadce.dll!4d142c9b()       
       msado15.dll!4bbe9e97()       
       msadce.dll!4d142d3f()       
       ntdll.dll!7c81d742()       
       ntdll.dll!7c81d77d()       
       ntdll.dll!7c82f9dd()       
       ntdll.dll!7c87551a()       
       ntdll.dll!7c876f21()       
       ntdll.dll!7c876dff()       
>      msvcr80d.dll!_heap_alloc_base(unsigned int size=106)  Line 105 + 0x28 bytes      C
       msvcr80d.dll!_heap_alloc_dbg(unsigned int nSize=70, int nBlockUse=1, const char * szFileName=0x782e4e94, int nLine=141)  Line 409 + 0x9 bytes      C++
       msvcr80d.dll!_nh_malloc_dbg(unsigned int nSize=70, int nhFlag=0, int nBlockUse=1, const char * szFileName=0x782e4e94, int nLine=141)  Line 266 + 0x15 bytes      C++
       msvcr80d.dll!_malloc_dbg(unsigned int nSize=70, int nBlockUse=1, const char * szFileName=0x782e4e94, int nLine=141)  Line 189 + 0x1b bytes      C++
       mfc80ud.dll!CAfxStringMgr::Allocate(int nChars=26, int nCharSize=2)  Line 141 + 0x16 bytes      C++
       mfc80ud.dll!ATL::CSimpleStringT<wchar_t,1>::Fork(int nLength=26)  Line 794 + 0x26 bytes      C++
       mfc80ud.dll!ATL::CSimpleStringT<wchar_t,1>::PrepareWrite2(int nLength=26)  Line 835 + 0xc bytes      C++
       mfc80ud.dll!ATL::CSimpleStringT<wchar_t,1>::PrepareWrite(int nLength=26)  Line 824      C++
       mfc80ud.dll!ATL::CSimpleStringT<wchar_t,1>::Preallocate(int nLength=26)  Line 529      C++
       mfc80ud.dll!ATL::CSimpleStringT<wchar_t,1>::SetString(const wchar_t * pszSrc=0x00cd3bf0, int nLength=26)  Line 643 + 0xc bytes      C++
       mfc80ud.dll!ATL::CSimpleStringT<wchar_t,1>::SetString(const wchar_t * pszSrc=0x00cd3bf0)  Line 620      C++
       mfc80ud.dll!ATL::CSimpleStringT<wchar_t,1>::operator=(const wchar_t * pszSrc=0x00cd3bf0)  Line 340      C++
       mfc80ud.dll!ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >::operator=(const wchar_t * pszSrc=0x00cd3bf0)  Line 1282      C++
       mfc80ud.dll!ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >(const wchar_t * pszSrc=0x00cd3bf0)  Line 1059      C++
       MzAppBase.dll!Mz_sAreaLeaf::GetVomChar()  Line 149 + 0x5e bytes      C++
       MzAppBase.dll!MzTabChar::Initialize(ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > > objectType="Area")  Line 60 + 0xe bytes      C++
       MzAppBase.dll!Mz_sAreaView::DoRecordsetExchange(CDataExchange * pDX=0x00123698)  Line 97      C++
       MzGUI.dll!MzFormView::UpdateRecordsets(bool bSaveAndValidate=false)  Line 146      C++


So, my first thought was that I had a corrupt heap, which made me my fill my code with:
int result = HeapValidate(GetProcessHeap(), HEAP_NO_SERIALIZE, NULL);
But even when that line was the one right before the MyFunc(_T("a string")); call, it showed no errors in the heap... (return code=1)

The errors seems to happen at a few places, but not ALWAYS at the same place...

I'm totally puzzeled to what the problem might be... I have tried rebuilding the whole solution (7 projects which produce 2 libs, 4 dlls and one exe), but no improvement...

Anyone have any idea what the problem might be? I can't post all of the source here, but feel free to ask if I have left out any vital piece of info.
0
Comment
Question by:kittelmann
13 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 16926004
void MyFunc(CString parameter)

Not the best way to pass strings between functions. Replacing parameter with LPCTSTR both fixes this problem and improves perfirmance:

void MyFunc(LPCTSTR parameter)
0
 

Author Comment

by:kittelmann
ID: 16926050
Well, you may have a point, but CString is very convenient to have and use compared to LPCTSTR...

Also, I have quite a few "modules" (classes from others (like www.codeproject.com)) that uses CString, so I can't totally get rid of CString.

And, since I can't see that I'm doing something wrong with my use of CString, I'd rather not spend the many, many hours of work to remove CString from my project. (I checked and the word CString ocurs on 3363 lines of my code...). And even if I did, I'm not sure that would solve this problem if the problem is in fact a reaction to something else that's wrong.
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 16926122
It is not necessary to remove CString. Just don't use it as parameter:

void MyFunc(LPCTSTR new_parameter)
{
    CString parameter = new_parameter;
    // continue to work with parameter  variavle
    ...
}

This function can be called using CString instance:
CString s;
...
MyFunc(s);

because CString has casting LPCTSTR operator. So, you need to make small change only in functions which have CString parameter, without changing the code which calls them.

About your code:
MzAppBase.dll!MzTabChar::Initialize(ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > > objectType="Area")  Line 60 + 0xe bytes     C++

Can you show this function and function which calls it. Maybe there is some error that I can see.
0
 

Author Comment

by:kittelmann
ID: 16926352
It scares me to do the changes you propose... especially since I see no real error in the way I do it, and since it works in VS2003. Prehaps I could do the changes to the places when I get an exception now, and see if it solves the problem...

Ok, the functions are as follows:

void MzTabChar::Initialize(CString objectType)
{
      m_objectType = objectType;

      if (m_objectType == _T("Module"))
      {
            m_vomChar = ((Mz_sModuleLeaf *)m_treeLeaf)->GetVomChar();
            m_staticChar.SetWindowText(_T("CHARACTER_APPEARS_IN_MODULE:"));
      }
      else if (m_objectType == _T("Area"))
      {
            m_vomChar = ((Mz_sAreaLeaf *)m_treeLeaf)->GetVomChar();
            m_staticChar.SetWindowText(_T("CHARACTER_APPEARS_IN_AREA:"));      
      }
      else
      {
            MZASSERT(false);
      }

      SetNumberInTitle(m_vomChar->GetNumRows());

      m_listChar.RegisterDropHandler(StaticListDropHandler, this);
}

MzVoItem *Mz_sAreaLeaf::GetVomChar()
{
      if (m_vomChar)
            return m_vomChar;
      m_vomChar = (MzVoItem *)g_theMzCachedInfo->GetVO(this, _T("Item"), _T("FetchCharactersConnectedTo"), m_vosArea->GetID(), 0, _T("Area"));
      return m_vomChar;
}

void Mz_sAreaView::DoRecordsetExchange(CDataExchange *pDX)
{
      if (pDX->m_bSaveAndValidate)                        
      {
            //Code not reached in this case.
      }
      else                                                            
      {
            m_editName.SetWindowText(m_vosArea->GetString(_T("Name"), 1));
            m_editDescInt.SetWindowText(m_vosArea->GetString(_T("DescriptionInternal"), 1));
            m_editDescEx.SetWindowText(m_vosArea->GetString(_T("DescriptionExternal"), 1));
            
            m_tabArea.Initialize(_T("Area")); //Calls MzTabChar::Initialize due to inheritance
            m_tabChar.Initialize(_T("Area")); //Calls MzTabChar::Initialize due to inheritance
            m_tabDoc.Initialize(_T("Area")); //Calls MzTabChar::Initialize due to inheritance
            m_tabItem.Initialize(_T("Area")); //Calls MzTabChar::Initialize due to inheritance
            m_tabSit.Initialize(_T("Area")); //Calls MzTabChar::Initialize due to inheritance

            m_tabAssoc.Invalidate();
      }
      m_tabAssoc.DoRecordsetExchange(pDX);
}
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 16926378
This happens in GetVomChar, when is constructs CStringT instance to pass it to GetVO function. You need to debug this and see what happens exactly.
My guess that your program has bug which was not detected in previous versions. I am not sure that it is related to CString parameters.
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 

Author Comment

by:kittelmann
ID: 16926781
Thanks for the attempt to help me. I tried debugging and it looks correct in the code I have the source for. The error must be due to something that affects ntdll which I can't see... (and I'm not sure I'd beable to understand all of it either...)

I tried doing what you suggested and send only LPCTSTR parameters and then doing a
MyFunc(LPCTSTR param)
{
  CString newParam = param;
  <some other code>
}

but that line "CString newParam = param;" crashes just as the function call did before... :-(

I'll do one last try and see what happens if I release compile the whole solution (since the call stack passes debug versions of malloc and free).

Otherwise I'll just have to go back to VS2003.

Thanks for your time.
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 16926821
What is param value in the debugger?
0
 

Author Comment

by:kittelmann
ID: 16926855
the param value is "Area"... a normal unicode string...
0
 

Author Comment

by:kittelmann
ID: 17128529
This problem seems unsolvable. I have since a long time reverted to VS2003.

Suggest that this topic be closed or deleted.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 17349428
For what it's worth, Andy's suggestion to pass parameters as a LPCTSTR and convert to a CString as the first line in the code is a standard practice and an excellent suggestion.  When done that way, the ctor and dtor are in plain sight.. the CString is never temporary objects that the compiler needs to create behind the scenes.

It should work either way, so this may be a bug in the MS compiler.  I'm going to recommend that this Q be saved in the PAQ.
0
 

Accepted Solution

by:
CetusMOD earned 0 total points
ID: 17371180
PAQed with points refunded (250)

CetusMOD
Community Support Moderator
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now