Standard_OutOfMemory exception is refactored so as to avoid memory allocations (which will likely fail) when it is raised:
- method NewInstance() returns static instance (singleton)
- method Raise() raises copy of that singleton, resetting its message string
- message string is stored as field, not allocated dynamically (thus maximum message length is limited by buffer size)
Class Standard_Failure slightly revised: method Destroy() is merged to destructor, methods Get/SetMessageString() are made virtual.
Add test case for the bug
if (aResult == NULL)
{
char aBuf[128];
- Sprintf (aBuf, "Failed to allocate " PRIuPTR " bytes in local dynamic heap", theSize);
+ Sprintf (aBuf, "Failed to allocate %" PRIuPTR " bytes in local dynamic heap", theSize);
Standard_OutOfMemory::Raise (aBuf);
}
return aResult;
#include <gp_Ax2.hxx>
#include <Geom_Circle.hxx>
#include <Geom_SurfaceOfLinearExtrusion.hxx>
+#include <NCollection_List.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <TColStd_Array2OfReal.hxx>
#include <TColStd_Array1OfReal.hxx>
return 0;
}
+namespace AllocTest
+{
+ // The test is based of occupying of all available virtual memory.
+ // Obviously it has no sense on 64-bit platforms.
+
+ enum Status
+ {
+ NotApplicable = 0x1,
+ OUMCatchOK = 0x2,
+ OUMCatchFail = 0x4
+ };
+
+ template<int> int test()
+ {
+ // non-32-bit implementation
+ return NotApplicable;
+ }
+
+ template<> int test<4>()
+ {
+ // 32-bit implementation
+ NCollection_List<Standard_Address> aList;
+ const Standard_Integer aBlockSizes[] = {100000, 10000, 10};
+ int aStatus = 0;
+
+ // start populate memory with blocks of large size, then
+ // smaller ones and so on according to content of the array aBlockSizes
+ for (size_t i=0; i < sizeof(aBlockSizes)/sizeof(int); i++)
+ {
+ try
+ {
+ for (;;)
+ aList.Append(Standard::Allocate(aBlockSizes[i]));
+ }
+ catch (Standard_Failure)
+ {
+ aStatus |= OUMCatchOK;
+ }
+ catch (...)
+ {
+ aStatus |= OUMCatchFail;
+ break;
+ }
+ }
+ // release all allocated blocks
+ for (NCollection_List<Standard_Address>::Iterator it(aList); it.More(); it.Next())
+ {
+ Standard::Free(it.Value());
+ }
+ return aStatus;
+ }
+}
+
+//=======================================================================
+//function : OCC24836
+//purpose :
+//=======================================================================
+static Standard_Integer OCC24836 (Draw_Interpretor& theDI, Standard_Integer n, const char** a)
+{
+ if (n != 1)
+ {
+ theDI << "Usage : " << a[0] << "\n";
+ return 1;
+ }
+
+ int aStatus = AllocTest::test<sizeof(size_t)>();
+
+ if (aStatus & AllocTest::NotApplicable)
+ theDI << "This test case is not applicable for 64-bit and higher platforms\n";
+ if (aStatus & AllocTest::OUMCatchOK)
+ theDI << "out-of-memory has been caught: OK\n";
+ if (aStatus & AllocTest::OUMCatchFail)
+ theDI << "Error: out-of-memory is not always caught\n";
+ return 0;
+}
+
//=======================================================================
//function : OCC27021
const char *group = "QABugs";
theCommands.Add ("OCC26675_1", "OCC26675_1 result", __FILE__, SurfaceGenOCC26675_1, group);
+ theCommands.Add ("OCC24836", "OCC24836", __FILE__, OCC24836, group);
theCommands.Add("OCC27021", "OCC27021", __FILE__, OCC27021, group);
return;
Standard_ExtString.hxx
Standard_Failure.cxx
Standard_Failure.hxx
-Standard_Failure.lxx
Standard_GUID.cxx
Standard_GUID.hxx
Standard_Handle.hxx
Standard_NullValue.hxx
Standard_NumericError.hxx
Standard_OStream.hxx
+Standard_OutOfMemory.cxx
Standard_OutOfMemory.hxx
Standard_OutOfRange.hxx
Standard_Overflow.hxx
myMessage = copy_message(theFailure.myMessage);
}
-void Standard_Failure::Destroy()
+Standard_Failure::~Standard_Failure()
{
deallocate_message(myMessage);
}
{
return new Standard_Failure(AString) ;
}
+
+//=======================================================================
+//function : GetMessageString
+//purpose : Returns error message
+//=======================================================================
+Standard_CString Standard_Failure::GetMessageString () const
+{
+ return (myMessage ? myMessage+sizeof(Standard_Integer) : "");
+}
+
//! Creates a status object of type "Failure".
Standard_EXPORT Standard_Failure();
-Standard_EXPORT Standard_Failure (const Standard_Failure& f);
-
+
+ //! Copy constructor
+ Standard_EXPORT Standard_Failure (const Standard_Failure& f);
//! Creates a status object of type "Failure".
Standard_EXPORT Standard_Failure(const Standard_CString aString);
-Standard_EXPORT Standard_Failure& operator= (const Standard_Failure& f);
-
- Standard_EXPORT void Destroy();
-~Standard_Failure()
-{
- Destroy();
-}
+
+ //! Assignment operator
+ Standard_EXPORT Standard_Failure& operator= (const Standard_Failure& f);
+ //! Destructor
+ Standard_EXPORT ~Standard_Failure();
//! Prints on the stream <s> the exception name followed by
//! the error message.
//! Handle(Standard_Failure)&)"
//! is implemented. (This operator uses the method Print)
Standard_EXPORT void Print (Standard_OStream& s) const;
-void operator<< (Standard_OStream& s) const
-{
- Print(s);
-}
//! Returns error message
- Standard_CString GetMessageString() const;
+ Standard_EXPORT virtual Standard_CString GetMessageString() const;
//! Sets error message
- Standard_EXPORT void SetMessageString (const Standard_CString aMessage);
+ Standard_EXPORT virtual void SetMessageString (const Standard_CString aMessage);
Standard_EXPORT void Reraise();
};
-
-#include <Standard_Failure.lxx>
-
-
-
-
+inline Standard_OStream& operator << (Standard_OStream& AStream,
+ const Handle(Standard_Failure)& AFailure)
+{
+ AFailure->Print(AStream);
+ return AStream;
+}
#endif // _Standard_Failure_HeaderFile
+++ /dev/null
-// Copyright (c) 1998-1999 Matra Datavision
-// Copyright (c) 1999-2014 OPEN CASCADE SAS
-//
-// This file is part of Open CASCADE Technology software library.
-//
-// This library is free software; you can redistribute it and/or modify it under
-// the terms of the GNU Lesser General Public License version 2.1 as published
-// by the Free Software Foundation, with special exception defined in the file
-// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
-// distribution for complete text of the license and disclaimer of any warranty.
-//
-// Alternatively, this file may be used under the terms of Open CASCADE
-// commercial license or contractual agreement.
-
-// ------------------------------------------------------------------
-// Print (me; s: in out OStream) returns OStream;
-// ------------------------------------------------------------------
-//++++ void Standard_Failure::Print (Standard_OStream& AStream) const
-//++++ {
-//++++ AStream << ": " << myMessage << endl;
-
-inline Standard_OStream& operator <<(Standard_OStream& AStream,
- const Handle(Standard_Failure)& AFailure)
-{
- AFailure->Print(AStream);
- return AStream;
-}
-
-//=======================================================================
-//function : GetMessageString
-//purpose : Returns error message
-//=======================================================================
-inline Standard_CString Standard_Failure::GetMessageString () const
-{
- return (myMessage ? myMessage+sizeof(Standard_Integer) : myMessage);
-}
-
#define GET_USER(block) (((Standard_Size*)(block)) + BLOCK_SHIFT)
#define GET_BLOCK(storage) (((Standard_Size*)(storage))-BLOCK_SHIFT)
-// create static instance of out-of-memory exception to protect
-// against possible lack of memory for its raising
-static Handle(Standard_OutOfMemory) anOutOfMemError = new Standard_OutOfMemory;
-
//=======================================================================
//function : Standard_MMgr
//purpose :
aBlock = (Standard_Size*)calloc(RoundSizeN+BLOCK_SHIFT, sizeof(Standard_Size));
// if still not succeeded, raise exception
if ( ! aBlock )
- anOutOfMemError->Reraise ("Standard_MMgrOpt::Allocate(): malloc failed");
+ Standard_OutOfMemory::Raise ("Standard_MMgrOpt::Allocate(): malloc failed");
}
// initialize new block header by its size
if ( Purge(Standard_False) )
goto retry;
// if nothing helps, raise exception
- anOutOfMemError->Reraise (strerror(errcode));
+ Standard_OutOfMemory::Raise (strerror(errcode));
}
// save actually allocated size into argument
char message[BUFSIZE];
if ( FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, message, BUFSIZE-1, 0) <=0 )
strcpy (message, "Standard_MMgrOpt::AllocMemory() failed to mmap");
- anOutOfMemError->Reraise (message);
+ Standard_OutOfMemory::Raise (message);
}
// record map handle in the beginning
if ( Purge(Standard_False) )
goto retry;
// if nothing helps, raise exception
- anOutOfMemError->Reraise ("Standard_MMgrOpt::Allocate(): malloc failed");
+ Standard_OutOfMemory::Raise ("Standard_MMgrOpt::Allocate(): malloc failed");
}
}
// clear whole block if clearing option is set
--- /dev/null
+// Created on: 2016-01-06
+// Created by: Andrey Betenev
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Standard_OutOfMemory.hxx>
+
+#include <algorithm>
+#include <stdlib.h>
+
+IMPLEMENT_STANDARD_RTTIEXT(Standard_OutOfMemory,Standard_ProgramError)
+
+//=======================================================================
+//function : Standard_OutOfMemory
+//purpose :
+//=======================================================================
+
+Standard_OutOfMemory::Standard_OutOfMemory(const Standard_CString theMessage)
+{
+ // call explicitly own method (non-virtual call)
+ Standard_OutOfMemory::SetMessageString (theMessage);
+}
+
+//=======================================================================
+//function : GetMessageString
+//purpose :
+//=======================================================================
+
+Standard_CString Standard_OutOfMemory::GetMessageString() const
+{
+ return myBuffer;
+}
+
+//=======================================================================
+//function : SetMessageString
+//purpose :
+//=======================================================================
+
+void Standard_OutOfMemory::SetMessageString (const Standard_CString theMessage)
+{
+ // restrict length of the message by buffer size
+ size_t n = (theMessage ? std::min (strlen (theMessage), sizeof(myBuffer) - 1) : 0);
+
+ // first set line end symbol to be safe in case of concurrent call
+ myBuffer[n] = '\0';
+ if (n > 0)
+ memcpy (myBuffer, theMessage, n);
+}
+
+//=======================================================================
+//function : Raise
+//purpose :
+//=======================================================================
+
+void Standard_OutOfMemory::Raise(const Standard_CString theMessage)
+{
+ NewInstance(theMessage)->Reraise();
+}
+
+//=======================================================================
+//function : Raise
+//purpose :
+//=======================================================================
+
+void Standard_OutOfMemory::Raise(Standard_SStream& theMessage)
+{
+ NewInstance(theMessage.str().c_str())->Reraise();
+}
+
+//=======================================================================
+//function : NewInstance
+//purpose :
+//=======================================================================
+
+// global instance must be allocated at load-time
+static Handle(Standard_OutOfMemory) anOutOfMemInstance = new Standard_OutOfMemory;
+
+Handle(Standard_OutOfMemory) Standard_OutOfMemory::NewInstance(const Standard_CString theMessage)
+{
+ anOutOfMemInstance->SetMessageString (theMessage);
+ return anOutOfMemInstance;
+}
+
+//=======================================================================
+//function : Throw
+//purpose :
+//=======================================================================
+
+void Standard_OutOfMemory::Throw () const
+{
+ throw *this;
+}
#define Standard_OutOfMemory_Raise_if(CONDITION, MESSAGE)
#endif
-DEFINE_STANDARD_EXCEPTION(Standard_OutOfMemory, Standard_ProgramError)
+//! Standard_OutOfMemory exception is defined explicitly and not by
+//! macro DEFINE_STANDARD_EXCEPTION, to avoid necessity of dynamic
+//! memory allocations during throwing and stack unwinding:
+//!
+//! - method NewInstance() returns static instance (singleton)
+//! - method Raise() raises copy of that singleton, resetting
+//! its message string
+//! - message string is stored as field, not allocated dynamically
+//! (storable message length is limited by buffer size)
+//!
+//! The reason is that in out-of-memory condition any memory allocation can
+//! fail, thus use of operator new for allocation of new exception instance
+//! is dangerous (can cause recursion until stack overflow, see #24836).
+
+class Standard_OutOfMemory : public Standard_ProgramError
+{
+ void Throw () const Standard_OVERRIDE;
+
+public:
+
+ //! Constructor is kept public for backward compatibility
+ Standard_EXPORT Standard_OutOfMemory(const Standard_CString theMessage = 0);
+
+ //! Returns error message
+ Standard_EXPORT Standard_CString GetMessageString() const Standard_OVERRIDE;
+
+ //! Sets error message
+ Standard_EXPORT void SetMessageString (const Standard_CString aMessage) Standard_OVERRIDE;
+
+ //! Raises exception with specified message string
+ Standard_EXPORT static void Raise(const Standard_CString theMessage = "");
+
+ //! Raises exception with specified message string
+ Standard_EXPORT static void Raise(Standard_SStream& theMessage);
+
+ //! Returns global instance of exception
+ Standard_EXPORT static Handle(Standard_OutOfMemory) NewInstance(const Standard_CString theMessage = "");
+
+ DEFINE_STANDARD_RTTIEXT(Standard_OutOfMemory,Standard_ProgramError)
+
+protected:
+ char myBuffer[1024];
+};
#endif // _Standard_OutOfMemory_HeaderFile
--- /dev/null
+puts "============"
+puts "OCC24836"
+puts "============"
+puts ""
+#######################################################################
+# Stack overflow when raising exception in low memory condition
+#######################################################################
+
+pload QAcommands
+
+OCC24836