mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-19 13:40:49 +03:00
0024836: Stack overflow when raising exception in low memory condition
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
This commit is contained in:
@@ -29,7 +29,6 @@ Standard_ExtString.cxx
|
||||
Standard_ExtString.hxx
|
||||
Standard_Failure.cxx
|
||||
Standard_Failure.hxx
|
||||
Standard_Failure.lxx
|
||||
Standard_GUID.cxx
|
||||
Standard_GUID.hxx
|
||||
Standard_Handle.hxx
|
||||
@@ -62,6 +61,7 @@ Standard_NullObject.hxx
|
||||
Standard_NullValue.hxx
|
||||
Standard_NumericError.hxx
|
||||
Standard_OStream.hxx
|
||||
Standard_OutOfMemory.cxx
|
||||
Standard_OutOfMemory.hxx
|
||||
Standard_OutOfRange.hxx
|
||||
Standard_Overflow.hxx
|
||||
|
@@ -88,7 +88,7 @@ Standard_Failure::Standard_Failure (const Standard_Failure& theFailure)
|
||||
myMessage = copy_message(theFailure.myMessage);
|
||||
}
|
||||
|
||||
void Standard_Failure::Destroy()
|
||||
Standard_Failure::~Standard_Failure()
|
||||
{
|
||||
deallocate_message(myMessage);
|
||||
}
|
||||
@@ -195,3 +195,13 @@ Handle(Standard_Failure) Standard_Failure::NewInstance(const Standard_CString AS
|
||||
{
|
||||
return new Standard_Failure(AString) ;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : GetMessageString
|
||||
//purpose : Returns error message
|
||||
//=======================================================================
|
||||
Standard_CString Standard_Failure::GetMessageString () const
|
||||
{
|
||||
return (myMessage ? myMessage+sizeof(Standard_Integer) : "");
|
||||
}
|
||||
|
||||
|
@@ -41,19 +41,18 @@ public:
|
||||
|
||||
//! 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.
|
||||
@@ -63,16 +62,12 @@ Standard_EXPORT Standard_Failure& operator= (const Standard_Failure& f);
|
||||
//! 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();
|
||||
|
||||
@@ -133,11 +128,11 @@ private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
#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
|
||||
|
@@ -1,37 +0,0 @@
|
||||
// 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);
|
||||
}
|
||||
|
@@ -132,10 +132,6 @@ extern "C" int getpagesize() ;
|
||||
#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 :
|
||||
@@ -400,7 +396,7 @@ Standard_Address Standard_MMgrOpt::Allocate(const Standard_Size aSize)
|
||||
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
|
||||
@@ -725,7 +721,7 @@ retry:
|
||||
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
|
||||
@@ -759,7 +755,7 @@ retry:
|
||||
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
|
||||
@@ -782,7 +778,7 @@ retry:
|
||||
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
|
||||
|
102
src/Standard/Standard_OutOfMemory.cxx
Normal file
102
src/Standard/Standard_OutOfMemory.cxx
Normal file
@@ -0,0 +1,102 @@
|
||||
// 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;
|
||||
}
|
@@ -32,6 +32,48 @@ DEFINE_STANDARD_HANDLE(Standard_OutOfMemory, Standard_ProgramError)
|
||||
#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
|
||||
|
Reference in New Issue
Block a user