[Insight-developers] serious problem with new[] on MSVC++

Brad King brad.king at kitware.com
Mon, 03 May 2004 17:28:53 -0400


Charl P. Botha wrote:
> Dear developers,
> 
> Brad King wrote:
> 
>> Charl P. Botha wrote:
> 
> 
>>> It seems that, at least on MSVC, new (or new[]) does not throw an
>>> exception when failing to allocate memory[1][2].  Looking at for
>>> instance itk::ImportImageContainer::Reserve(), which does all the
>>> allocation for itk::Image (and thus for MANY of the ITK filters and
>>> sources), the return value of the new[] is not checked!
>>>
>>> I've seen this crash my applications on windows when working with large
>>> DICOM datasets.  The program silently continues running, until a filter
>>> writes to for example the output Image which has a NULL buffer (due to a
>>> failed new[] that wasn't caught).
>>>
>>> This can be fixed by installing a global new_handler function[3].  I've
>>> grepped through the ITK sources and couldn't find an invocation of
>>> _set_new_handler(), so I'm assuming no-one has done this.
>>>
>>> Any discussion (or corrections!) on this is welcome.  I'm not sure how
>>> new[] indicates failure on for instance the GCC compilers, but whatever
>>> the case may be, it's quite critical that this is handled *correctly* in
>>> ITK.  The ISO C++ spec says that new[] should throw (as far as I can
>>> see), but compilers don't always follow this to the letter, as is shown
>>> by this example.
>>
>>
>>
>> The C++ standard says that if a new or new[] operator is declared with 
>> an empty "throw()" specification then it should return NULL when 
>> failing to allocate memory.  Otherwise it should throw a 
>> std::bad_alloc exception.
>>
>> ITK has been written to assume that the exception is thrown and 
>> therefore never checks the results of allocation (which is the whole 
>> point of a throwing allocation routine).  However, ITK should not set 
>> anything that is of global process scope since it is a library.  The 
>> application should set the handler correctly if it wants to be robust 
>> to this problem.
>>
>> Another alternative is to send all ITK memory allocation through some 
>> function that tries to use new or new[] to alloate memory and then 
>> throws std::bad_alloc if it gets a NULL pointer back.  That way we can 
>> be sure the exception will be thrown no matter the default behavior 
>> provided by a compiler.
> 
> 
> Excuse the long quote, but this has been quite a while.
> 
> I just got bitten by this one again.  It's quite nasty: one's 
> application simply aborts and after the prerequisite debugging, one 
> realises that it's because MSVC++ 6.0 sp6 doesn't throw an exception 
> when a new[] allocation fails.  I'm not sure if .NET 2003 does the Right 
> Thing(tm).
> 
> Brad's proposed solution would definitely do the trick: checking the new 
> or new[] return value and throwing std::bad_alloc in the case of a NULL 
> in for instance itk::ImportImageContainer (this is where all itk::Image 
> allocation seems to take place) would do no harm on any of the currently 
> working C++ compilers, but would make life much easier with compilers 
> which do not raise exceptions for failing new invocations.

I've modified ImportImageContainer to throw itk::MemoryAllocationError 
when memory allocation fails.  We may want to change it to 
std::bad_alloc, but this approach requires fewer catch blocks in ITK 
programs.  Most of the tests catch only itk::ExceptionObject (and 
subclasses).

-Brad