CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 19
  1. #1
    Join Date
    Mar 2005
    Posts
    11

    Question Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Hi,

    I'm building an application for Windows CE and Windows Desktop. The cross compilation is possible using some preprocessor directive, a different VS project file and a different VS solution file.

    As my application must be robust, I need to test each memory allocation and in the case of an memory allocation failure . I want to be able to correctly clean the previously allocated resources.

    Here is an exemple to show you my actual problem :

    Code:
    #include <list>
    using namespace std;
    
    typedef struct _MyObject
    {
        int a[9999];
    } MyObject;
    
    int i = 0;
    MyObject p;
    list<MyObject> v;
    try
    {
        // Force failure
        for (; i < 999999; ++i)
        {
            v.push_back(p);
        }
    }
    catch(CMemoryException* er)
    {
        DEBUG_ALERT("CMemoryException !");
    }
    catch(std::bad_alloc& er)
    {
        DEBUG_ALERT("bad_alloc error !");
    }
    And the following file (NewHandler.cpp) is only include on Windows CE (To force a std::bad_alloc) uppon a memory failure. As Windows CE malloc returns NULL instead of throwing std::bad_alloc exception.

    Code:
    // http://msdn.microsoft.com/en-us/magazine/cc164087.aspx
    #include <new>
    #include <new.h>
    
    // 4073: initializers put in library initialization area
    #pragma warning(disable: 4073)
    
    #pragma init_seg(lib)
    
    namespace
    {
    
       int new_handler(size_t) 
       {
           throw std::bad_alloc();
           return 0;
       }
    
       class NewHandler
       {
       public:
           NewHandler() 
           {
               m_old_new_handler = _set_new_handler(new_handler);
           }
        
           ~NewHandler() 
           {
              _set_new_handler(m_old_new_handler);
           }
    
       private:
           _PNH m_old_new_handler;
    
       } g_NewHandler; 
    }
    On Windows Desktop the program allocate memory until a CMemoryException is thrown. This is the result I want also on Windows CE.

    On Windows CE, the program allocate memory until the device show a popup message with the message "Memory system is very low". So I cannot intercept the moment when the first allocation failed ! Result, my program crash and the device too ! Not wise !.

    Is there any way to circumvent this problem ?

    I don't understand how can we catch memory problem on Windows CE, if we have NO WAY to detect it ? Take the list container as exemple, the push_back function returns nothing (void) and it doesn't throw any exeption when failing. So how can I more secure my code about allocation failure ?

    Best regards,
    Martin

  2. #2
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Did you try using _set_new_mode?

    What exactly do you want your program to do in case memory cannot be allocated? Do you want to handle this locally in your code or do you just want to exit the application cleanly? In the latter case, with careful use of RAII you could just call exit in the new handler.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  3. #3
    Join Date
    Mar 2005
    Posts
    11

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Hi D_Drmmr,

    This is exactly what I've tried. I had put the link on top of the file newHandle.cpp

    http://msdn.microsoft.com/en-us/magazine/cc164087.aspx

    But it doesn't work. I've tried allowing memory in FOR loop and at a given time, the system displays a window that indicate "System memory very low". Then this window only allow you to click on an OK button that inevitably leads to a freeze the device OS.

    Someone else on another forum tell me that it is a normal condition, this is the responsability of the device OEM to remove or activate this window. Is that make sens ? If yes, then is there any way to desactivate it by code as we don't have the BSP code source ?

  4. #4
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Quote Originally Posted by Erakis View Post
    As my application must be robust, I need to test each memory allocation and in the case of an memory allocation failure . I want to be able to correctly clean the previously allocated resources.
    Nowhere in your sample are you calling operator new[] yourself.

    The flaw in your entire example is assuming that list::push_back() does what you think it does in terms of the C++ routines to allocate memory. Basically, if you don't see "new" or "new[]" called anywhere, you can't assume anything. What if the implementation uses malloc() and then placement-new? Wouldn't that bypass all of that code you have now, since placement-new doesn't really allocate anything? (all it does is place the pointer at the memory area that was malloc()-ed).

    Instead of this example, why not post a program that explicitly calls operator new[]? An example like this:

    http://msdn.microsoft.com/en-us/library/ms861441.aspx

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; November 15th, 2012 at 09:15 PM.

  5. #5
    Join Date
    Mar 2005
    Posts
    11

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Hi Paul,

    Whatever I'm using the vector by data value or I use a vector holding data pointer that I have to allocate manually using new or malloc, it gives the same result. The system display the memory low dialog and eventually freeze.

    It's just that I did not put the two examples in my previous post.

    Here is the second exemple :

    Code:
    #include <list>
    using namespace std;
    
    typedef struct _MyObject
    {
        int a[9999];
    } MyObject;
    
    int i = 0;
    MyObject* p = NULL;
    list<MyObject *> v;
    try
    {
        // Force failure
        for (; i < 999999; ++i)
        {
            p = new MyObject();
            v.push_back(p);
        }
    }
    catch(CMemoryException* er)
    {
        DEBUG_ALERT("CMemoryException !");
    }
    catch(std::bad_alloc& er)
    {
        DEBUG_ALERT("bad_alloc error !");
    }
    So, this is exactly the same problem

    Try by ourself and you will see...

    What I've found so far is this article from Microsoft (http://msdn.microsoft.com/en-us/library/ms911907.aspx) that indicate how control this low memory dialog. But even if I change the registry and go to not display it, is that it may remove some security necessary for the stability of Windows CE OS ?

    Martin

  6. #6
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Quote Originally Posted by Erakis View Post
    Hi Paul,

    Whatever I'm using the vector by data value or I use a vector holding data pointer that I have to allocate manually using new or malloc, it gives the same result. The system display the memory low dialog and eventually freeze.
    Let's start at a common baseline, and that is your system and the code given to you at the link I gave you.

    Please take the exact example posted at the link I gave you. Does it show the same issue? If it doesn't work, then we have something that has been posted at the Microsoft site that can be investigated. If the code does work, then there is something in your code that is different or causes different behaviour.

    I don't have Windows CE, so I can't test your code. What you should be doing is taking code that MS has given us on that site, and proving or disproving that the code there really works (assuming you have set up your project correctly, i.e. correct options for exception handling).

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; November 16th, 2012 at 12:26 PM.

  7. #7
    Join Date
    Mar 2005
    Posts
    11

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Hi Paul,

    Great new, I've retried and it's well working. But only if I'm doign the allocation by myself. Ex :

    Code:
    #include "new.h"
    #include <list>
    using namespace std;
    
    typedef struct _MyObject
    {
        int a[9999];
    } MyObject;
    
    
    
    int handle_program_memory_depletion( size_t )
    {
        ::AfxThrowMemoryException();
    }
    
    _set_new_handler( handle_program_memory_depletion );
    _set_new_mode(1);
    
    
    int i = 0;
    list<MyObject *> v;
    try
    {
        // Force failure
        for (; i < 999999; ++i)
        {
            v.push_back(new MyObject ());
        }
    }
    catch(CMemoryException* er)
    {
        DEBUG_ALERT("CMemoryException !");
        // I get the wanted exception here (IT NOW WORKING !!!)
    }
    catch(std::bad_alloc& er)
    {
        DEBUG_ALERT("bad_alloc error !");
    }

    BUT, this is not working if I'm pushing the data by value. Ex :

    Code:
    #include "new.h"
    #include <list>
    using namespace std;
    
    typedef struct _MyObject
    {
        int a[9999];
    } MyObject;
    
    
    
    int handle_program_memory_depletion( size_t )
    {
        ::AfxThrowMemoryException();
    }
    
    _set_new_handler( handle_program_memory_depletion );
    _set_new_mode(1);
    
    
    int i = 0;
    MyObject mo;
    list<MyObject> v;
    try
    {
        // Force failure
        for (; i < 999999; ++i)
        {
            v.push_back(mo);
        }
    }
    catch(CMemoryException* er)
    {
        DEBUG_ALERT("CMemoryException !");
        // I never get this exception !!!
    }
    catch(std::bad_alloc& er)
    {
        DEBUG_ALERT("bad_alloc error !");
    }
    Are you agree with me that when I push_back the mo object in the vector, the MyObject copy constructor will be called to create a new MyObject and it will be a member of the new NODE internally created by the Vector.

    From what I've see in the xmemory file of the stl, the new NODE created by the vector is allocated using the NEW oeprator . However, the preceeding code doesn't call the handle_program_memory_depletion handler. Instead I still get the "System very low memory" and the system completely freeze.

    So, why the new_handler doesn't affect the stl ???

    Best regards,
    Martin
    Last edited by Erakis; November 19th, 2012 at 12:21 PM.

  8. #8
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Quote Originally Posted by Erakis View Post
    Are you agree with me that when I push_back the mo object in the vector, the MyObject copy constructor will be called to create a new MyObject and it will be a member of the new NODE internally created by the Vector.
    If you are not calling "new" or "new[]" yourself, none of what you've stated is guaranteed to occur. There is no guarantee that copy construction is done under the hood, since copy construction can (and will be) optimized away by the compiler.
    From what I've see in the xmemory file of the stl, the new NODE created by the vector is allocated using the NEW oeprator .
    The "new" operator is just that -- an operator. There is no guarantee that each call to "new" allocates memory from the OS. The memory allocation is controlled by the heap manager. It's the heap manager that ultimately controls the allocations.

    Secondly, as stated before, there is placement-new. This form of "new" does not allocate memory -- instead another allocation is called (usually malloc), and the pointer is pointed to this area of memory by placement-new. You didn't mention what form of "new" is being called. I remember that some of the STL containers for Visual C++ uses placement new.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; November 19th, 2012 at 12:34 PM.

  9. #9
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Placement-new explained.

    http://www.parashift.com/c++-faq/placement-new.html

    Regards,

    Paul McKenzie

  10. #10
    Join Date
    Mar 2005
    Posts
    11

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Hi Paul,

    Here is a code part of the allocation in the STL vector xmemory file.

    Code:
    _STD_BEGIN
    		// TEMPLATE FUNCTION _Allocate
    template<class _Ty> inline
    	_Ty _FARQ *_Allocate(_SIZT _Count, _Ty _FARQ *)
    	{	// allocate storage for _Count elements of type _Ty
    	void *_Ptr = 0;
    
    	if (_Count <= 0)
    		_Count = 0;
    	else if (((_SIZT)(-1) / sizeof (_Ty) < _Count)
    		|| (_Ptr = ::operator new(_Count * sizeof (_Ty))) == 0)
    		_THROW_NCEE(bad_alloc, 0);
    
    	return ((_Ty _FARQ *)_Ptr);
    	}
    Unfortunately I don't see any PLACEMENT NEW, only a real NEW operator call. Therefore, in principle when there is no more memory available, the set_new_handler function should be called or I should get a stl::bad_alloc exception ? No ?

  11. #11
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Quote Originally Posted by Erakis View Post
    Hi Paul,

    Here is a code part of the allocation in the STL vector xmemory file.
    Your code is using std::list, not std::vector.

    Regards,

    Paul McKenzie

  12. #12
    Join Date
    Mar 2005
    Posts
    11

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Sorry I'm doing a lot of test to find a solution to this problem and I probably mix vector/list test code.

    Both of containers are using the same function _Ty _FARQ *_Allocate(_SIZT _Count, _Ty _FARQ *) internally to allocate memory.

    So whether it is a vector or a list, the new operator of (*_Allocate) function should trigger the new_handler in case of failure of memory allocation ?

    But obviously this is not the case.

  13. #13
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Quote Originally Posted by Erakis View Post
    Sorry I'm doing a lot of test to find a solution to this problem and I probably mix vector/list test code.
    You're also mixing MFC exceptions with STL exceptions. That's what's confusing about your code. I don't see how your code could have compiled using the MFC classes, given that you didn't specify the headers for them. If you're going to see if new failed, then the exception to catch is std::bad_alloc.

    Also, there is a difference between the global operator new() and the one for your class. Operator new() can be overloaded.

    Did you debug into the new() operator when you call it yourself, as opposed to when the runtime uses operator new()? You should see that the code is different, since it is impossible for the same code to do different things.

    Also, what version of Visual C++ are you using? I just had this very small program:
    Code:
    #include <list>
    using namespace std;
    
    struct MyObject
    {
        int x;
    };
    
    int main()
    {
        std::list<MyObject> lx;
        lx.push_back(MyObject());
    }
    I am using Visual Studio 2008. The following code is eventually called to construct the object:
    Code:
    template<class _T1,
    	class _T2> inline
    	void _Construct(_T1 _FARQ *_Ptr, const _T2& _Val)
    	{	// construct object at _Ptr with value _Val
    	void _FARQ *_Vptr = _Ptr;
    	::new (_Vptr) _T1(_Val);
    	}
    That line in red is the placement-new I was referring to.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; November 19th, 2012 at 04:57 PM.

  14. #14
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Quote Originally Posted by Erakis View Post
    Sorry I'm doing a lot of test to find a solution to this problem and I probably mix vector/list test code.

    Both of containers are using the same function _Ty _FARQ *_Allocate(_SIZT _Count, _Ty _FARQ *) internally to allocate memory.

    So whether it is a vector or a list, the new operator of (*_Allocate) function should trigger the new_handler in case of failure of memory allocation ?

    But obviously this is not the case.
    In general, these kind of discussions can be avoided by providing a minimally complete example that shows the problem. Your problem doesn't seem to have anything to do with std::vector or std::list. All you need to show the problem is maybe a 10-line program that sets the new handler, new mode and causes an allocation to fail. Based on such a program it's easier to figure out what's really going on, because you (and others) are not distracted by irrelevant issues.

    Based on your descriptions, I wonder if the issue has to do with the (configuration of the) OS. I'm not familiar with CE, but I could imagine that what's happening is that the OS is not able to expand the memory space for your program any more, e.g. because there is not enough disk space for the virtual memory.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  15. #15
    Join Date
    Mar 2005
    Posts
    11

    Post Re: Windows CE (STL + std::bad_alloc + CMemoryException, ...)

    Hi Paul,

    As I said, I'm building a project that is running on Windows Desktop and also on Windows CE. The code is the same, the Visual Studio project and solution are different.

    From MSDN :

    On Windows Desktop, when the new operator failed a CMemoryException is thrown.

    On Windows CE, when the new operator failed a NULL pointer is return and no exception is thrown. This is why I'm throwing a CMemoryException manually, on my new handler, simply to be able to use the Windows Desktop code as :


    Code:
    CDummy* p = NULL;
    try
    {
         p = new CDummy(...) ;
    }
    catch (CMemoryException* e)
    {
        e->Delete();
    
         // On Windows Desktop, if the memory failed, this exception will be catch.
    
         // On Windows CE, if memory failed and the set_new_handler works, than 
         // a CMemoryException will be thrown and this is where it will be catched.
    }
    What I can say, is ALL is well working on Windows Desktop. Whatever the memory allocation failure, whether in a manual new or a push_back by value in a stl container, a CMemoryException is thrown by the system. Even without using the set_new_handler !

    On Windows CE, this is another story. On a MANUAL NEW OPERATION, the system return a NULL pointer when the allocation failed so I must throw a CMemoryException manually. This is well working if I'm using the set_new_handler ! Thus, problem resolved for this case.

    Now here's where it still does not work :

    Complete sample code (MFCWindowsCETestMemory.cpp) on Windows CE
    Code:
    #include "stdafx.h"
    #include "MFCWindowsCETestMemory.h"
    #include "MFCWindowsCETestMemoryDlg.h"
    #include "new.h"
    #include <list>
    using namespace std;
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    // New handler declaration
    int handle_program_memory_depletion( size_t )
    {
        ::AfxThrowMemoryException();
    }
    
    
    // CMFCWindowsCETestMemoryApp
    
    BEGIN_MESSAGE_MAP(CMFCWindowsCETestMemoryApp, CWinApp)
    END_MESSAGE_MAP()
    
    
    // CMFCWindowsCETestMemoryApp construction
    CMFCWindowsCETestMemoryApp::CMFCWindowsCETestMemoryApp()
    	: CWinApp()
    {
    	// TODO: add construction code here,
    	// Place all significant initialization in InitInstance
    }
    
    // The one and only CMFCWindowsCETestMemoryApp object
    CMFCWindowsCETestMemoryApp theApp;
    
    // CMFCWindowsCETestMemoryApp initialization
    
    BOOL CMFCWindowsCETestMemoryApp::InitInstance()
    {
        // Set new handler
        _set_new_handler( handle_program_memory_depletion );
        _set_new_mode(1);
    
        list<MyObject> v;
        try
        {
            // Force failure
            for (int i = 0; i < 999999; ++i)
            {
    	v.push_back(MyObject());
            }
        }
        catch(CMemoryException* er)
        {
             er->Delete();
             DEBUG_ALERT("CMemoryException !");
             // This exception is never fired, instead the system show the Low Memory Dialog 
             // and the system freeze !
         }
         catch(std::bad_alloc& er)
         {
            const CHAR* c = er.what();
            //DEBUG_ALERT("bad_alloc error !");
            // This exception is never fired, instead the system show the Low Memory Dialog 
            // and the system freeze !
          }
    
          // Don't run the dialog, just for the test
          return FALSE;
    
          // Show main dialog
          CMFCWindowsCETestMemoryDlg dlg;
          m_pMainWnd = &dlg;
          INT_PTR nResponse = dlg.DoModal();
          if (nResponse == IDOK)
          {
                // TODO: Place code here to handle when the dialog is
                //  dismissed with OK
          }
    
          // Since the dialog has been closed, return FALSE so that we exit the
          //  application, rather than start the application's message pump.
          return FALSE;
    }
    While debugging on my Visual Studio 2005 (SmartDevice project), the callstack of the preceding code leads me to this piece of code :
    Code:
    _STD_BEGIN
    		// TEMPLATE FUNCTION _Allocate
    template<class _Ty> inline
    	_Ty _FARQ *_Allocate(_SIZT _Count, _Ty _FARQ *)
    	{	// check for integer overflow
    	if (_Count <= 0)
    		_Count = 0;
    	else if (((_SIZT)(-1) / _Count) < sizeof (_Ty))
    		_THROW(std::bad_alloc, NULL);
    
    		// allocate storage for _Count elements of type _Ty
    		return ((_Ty _FARQ *)::operator new(_Count * sizeof (_Ty)));;
    
    	}
    From What I notice in the template code, there no PLACEMENT new elsewhere ? It is a regular NEW ? Thus, if the allocation failed, my new_handler was not supposed to be called ?

    Even if the allocation was made on a PLACEMENT NEW, as the stl container would swell, he should allocate memory somewhere for his placement area. So if this operation fails, then my new_handler should be called. Not ? As I see here, this is not the case...

    PS : On Windows CE I've tried debuggin on the Visual Studio WinCE emulator using the STANDARD SDK and also debuggin directly on my WinCE Device with is SDK. This is the same behavior !
    Last edited by Erakis; November 20th, 2012 at 11:17 AM.

Page 1 of 2 12 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured