15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Stack overflow while serializing large object network in MFC

Bart van Haaff -- BARTHAAF@docuaccess.nl
Tuesday, November 26, 1996


Environment: MSVC1.52, NT4.0

Hi,

I try to serialize a pretty large and complex network of objects using   
MFC's serialize method. This works fine for me until a certain limit in   
the number of objects has been reached, My app crashes because of a stack   
overflow (current stack size 42 Kb, and I do not have any more space in   
the data segment).

I have tried the following code to enlarge stack but this crashes on the   
statement:
 ar >> m_pRootObject;

The crash happens immediate when I hit 'Step into (F8)' in the debugger.

// testcode
void CMyDoc::Serialize(CArchive& ar)
{
 // save some things in statics to survive stack switch
 static CMyRootClass* pRootObject=NULL;
         static CString strFileName=GetPathName();

 HANDLE hStack=GlobalAlloc(GPTR,63L*1024L);
 LPSTR pStack=(LPSTR)GlobalLock(hStack);
 // some obscure win3.0 API call
 SwitchStackTo(HIWORD(pStack),(UINT)(63L*1024L),0);
 // normal serialize code
 CFile f;  
 if(f.Open(strFileName, CFile::modeRead))
 {
  CArchive ar(&f,CArchive::load);
  // hit F8 to crash.....
  ar >> m_pRootObject;
 }
 ar.Close();
 f.Close();
 SwitchStackBack();
 GlobalUnlock(hStack);
 GlobalFree(hStack);
}

The nature of serialize() is recursive and there is not much to do about   
that, I checked out MFC's source code and the CArchive and CRuntimeClass   
read/write code, there are some non-static local variables in the code   
that eat a little stack space for each recursive level. In my own   
serialize code I declared all locals as 'static'.

I hope somebody can give some tips/hints, please don't tell me to:
* use 32-bits (I know, but my customers don't)
* change the structure of my object model (its to late for that)
* stop using MFC (I like some parts of it)

Thanks a lot....

Bart van Haaff (barthaaf@docuaccess.nl)
Senior Software Developer
Document Access B.V.
The Netherlands




Alexander Sasha Grinshpun -- alexgr@mercury.co.il
Thursday, November 28, 1996

You don't have to change your object model, just change the way your
network of objects are serialized. Let's take a look at pseudocode of
serializing a graph.

class Node {
  SomeUsefullData data;
  ListOfPointersToEdge edges;
  Serialize(CArchive &ar) {
    data.Serialize(ar);
    edges.Serialize(ar); // (1)
  };
};

class Edge {
  Node *source;
  Node *target;
  Serialize(CArchive &ar) {
    if(ar.IsLoading()) {
      ar >> source;
      // Here we may enter into a deep recursion because target may be
      //  not serialized yet
      ar >> target;
    } else {
      ar << source;
      ar << target;
    }
  }
};


class Graph {
  ListOfPointerToNodes nodes;
  
  Serialize(CArchive &ar) {
     nodes.Serialize(ar);
  }
};

Such a serialization of the Graph will cause a deep Serialize recursion.
The cause of this recursion is serialization of the edges of the node
inside the node itself. The following change in serialization will
fix the problem:

Node::Serialize(ar) {
  // We are serializing just a data and delegating responsibility
  // of graph structure serializing to Graph itself
  data.Serialize(ar);
}

Graph::Serialize(ar) {
   nodes.Serialize();
   // Pay attention, that here we will not enter a deep recursion in the
   // edge serialization because all nodes are already serialized
   for eache pnode in nodes {
     pnode->edges.Serialize();
   }
}

I hope it's helpful for you.

--
Sasha.

Bart van Haaff wrote:
> 
> Environment: MSVC1.52, NT4.0
> 
> Hi,
> 
> I try to serialize a pretty large and complex network of objects using
> MFC's serialize method. This works fine for me until a certain limit in
> the number of objects has been reached, My app crashes because of a stack
> overflow (current stack size 42 Kb, and I do not have any more space in
> the data segment).
> 
> I have tried the following code to enlarge stack but this crashes on the
> statement:
>  ar >> m_pRootObject;
> 
> The crash happens immediate when I hit 'Step into (F8)' in the debugger.
> 
> // testcode
> void CMyDoc::Serialize(CArchive& ar)
> {
>  // save some things in statics to survive stack switch
>  static CMyRootClass* pRootObject=NULL;
>          static CString strFileName=GetPathName();
> 
>  HANDLE hStack=GlobalAlloc(GPTR,63L*1024L);
>  LPSTR pStack=(LPSTR)GlobalLock(hStack);
>  // some obscure win3.0 API call
>  SwitchStackTo(HIWORD(pStack),(UINT)(63L*1024L),0);
>  // normal serialize code
>  CFile f;
>  if(f.Open(strFileName, CFile::modeRead))
>  {
>   CArchive ar(&f,CArchive::load);
>   // hit F8 to crash.....
>   ar >> m_pRootObject;
>  }
>  ar.Close();
>  f.Close();
>  SwitchStackBack();
>  GlobalUnlock(hStack);
>  GlobalFree(hStack);
> }
> 
> The nature of serialize() is recursive and there is not much to do about
> that, I checked out MFC's source code and the CArchive and CRuntimeClass
> read/write code, there are some non-static local variables in the code
> that eat a little stack space for each recursive level. In my own
> serialize code I declared all locals as 'static'.
> 
> I hope somebody can give some tips/hints, please don't tell me to:
> * use 32-bits (I know, but my customers don't)
> * change the structure of my object model (its to late for that)
> * stop using MFC (I like some parts of it)
> 
> Thanks a lot....
> 
> Bart van Haaff (barthaaf@docuaccess.nl)
> Senior Software Developer
> Document Access B.V.
> The Netherlands

-- 
----
Thanks,
Sasha.



rick cameron -- rick_cameron@msn.com
Thursday, November 28, 1996

We had a similar problem. Our solution was to change the serialization code.

Our document contains a list of sections; each section has a list of objects. 
An object may be attached to a guideline, and a guideline may connect objects 
in several sections.

We found that the following was happening:

document serializes first section
section serializes objects
object serializes guideline
guideline serializes all attached objects (which may jump into another 
section)
object serializes its section
section serializes objects
...etc...

It was possible for all objects to be serialized as a result of the call to 
serialize the first section - and, if there were several guidelines, recursion 
could become quite deep.

The solution was to change the Serialize member of the guideline class so that 
it didn't serialize its attached objects. When loading the document, each 
object reattaches itself to its guideline.

The reason I've gone into some detail is to point out that there may be a way 
that you can change your serialization code to reduce the amount of 
cross-coupling and recursion, without changing your object model. Instead of 
serializing a pointer to an object, reconnect when loading.

- rick

owner-mfc-l@majordomo.netcom.com on behalf of Bart van Haaff wrote:
> 
> Environment: MSVC1.52, NT4.0
> 
> Hi,
> 
> I try to serialize a pretty large and complex network of objects using   
> MFC's serialize method. This works fine for me until a certain limit in   
> the number of objects has been reached, My app crashes because of a stack   
> overflow (current stack size 42 Kb, and I do not have any more space in   
> the data segment).
> 
> I have tried the following code to enlarge stack but this crashes on the   
> statement:
>  ar >> m_pRootObject;
> 
> The crash happens immediate when I hit 'Step into (F8)' in the debugger.
> 
> // testcode
> void CMyDoc::Serialize(CArchive& ar)
> {
>  // save some things in statics to survive stack switch
>  static CMyRootClass* pRootObject=NULL;
>          static CString strFileName=GetPathName();
> 
>  HANDLE hStack=GlobalAlloc(GPTR,63L*1024L);
>  LPSTR pStack=(LPSTR)GlobalLock(hStack);
>  // some obscure win3.0 API call
>  SwitchStackTo(HIWORD(pStack),(UINT)(63L*1024L),0);
>  // normal serialize code
>  CFile f;  
>  if(f.Open(strFileName, CFile::modeRead))
>  {
>   CArchive ar(&f,CArchive::load);
>   // hit F8 to crash.....
>   ar >> m_pRootObject;
>  }
>  ar.Close();
>  f.Close();
>  SwitchStackBack();
>  GlobalUnlock(hStack);
>  GlobalFree(hStack);
> }
> 
> The nature of serialize() is recursive and there is not much to do about   
> that, I checked out MFC's source code and the CArchive and CRuntimeClass   
> read/write code, there are some non-static local variables in the code   
> that eat a little stack space for each recursive level. In my own   
> serialize code I declared all locals as 'static'.
> 
> I hope somebody can give some tips/hints, please don't tell me to:
> * use 32-bits (I know, but my customers don't)
> * change the structure of my object model (its to late for that)
> * stop using MFC (I like some parts of it)
> 
> Thanks a lot....
> 
> Bart van Haaff (barthaaf@docuaccess.nl)
> Senior Software Developer
> Document Access B.V.
> The Netherlands
> 
> 





| Вернуться в корень Архива |