I am having trouble understanding how clang throws exceptions when I try to allocate an object that would exceed its limit. For instance if I compile and run the following bit of code:
#include <limits>
#include <new>
#include <iostream>
int main(int argc, char** argv) {
typedef unsigned char byte;
byte*gb;
try{
gb=new byte[std::numeric_limits<std::size_t>::max()];
}
catch(const std::bad_alloc&){
std::cout<<"Normal"<<std::endl;
return 0;}
delete[]gb;
std::cout<<"Abnormal"<<std::endl;
return 1;
}
then when I compile using "clang++ -O0 -std=c++11 main.cpp" the result I get is "Normal" as expected, but as soon as I enable optimizations 1 through 3, the program unexpectedly returns "Abnormal".
I am saying unexpectedly, because according to the C++11 standard 5.3.4.7:
When the value of the expression in a noptr-new-declarator is zero, the allocation function is called to
allocate an array with no elements. If the value of that expression is less than zero or such that the size
of the allocated object would exceed the implementation-defined limit, or if the new-initializer is a braced-
init-list for which the number of initializer-clauses exceeds the number of elements to initialize, no storage
is obtained and the new-expression terminates by throwing an exception of a type that would match a
handler (15.3) of type std::bad_array_new_length (18.6.2.2).
[This behavior is observed with both clang 3.5 using libstd++ on linux and clang 3.3 using libc++ on Mac. The same behavior is also observed when the -std=c++11 flag is removed.]
The plot thickens when I compile the same program using gcc 4.8, using the exact same command line options. In that case, the program returns "Normal" for any chosen optimization level.
I cannot find any undefined behavior in the code posted above that would explain why clang would feel free not to throw an exception when code optimizations are enabled. As far as the bug database is concerned, the closest I can find is http://llvm.org/bugs/show_bug.cgi?id=11644 but it seems to be related to the type of exception being thrown rather than a behavior difference between debug and release code.
So it this a bug from Clang? Or am I missing something? Thanks,
It appears that clang eliminates the allocation as the array is unused:
#include <limits>
#include <new>
#include <iostream>
int main(int argc, char** argv)
{
typedef unsigned char byte;
bytes* gb;
const size_t max = std::numeric_limits<std::size_t>::max();
try
{
gb = new bytes[max];
}
catch(const std::bad_alloc&)
{
std::cout << "Normal" << std::endl;
return 0;
}
try
{
gb[0] = 1;
gb[max - 1] = 1;
std::cout << gb[0] << gb[max - 1] << "\n";
}
catch ( ... )
{
std::cout << "Exception on access\n";
}
delete [] gb;
std::cout << "Abnormal" << std::endl;
return 1;
}
This code prints "Normal"
with -O0 and -O3, see this demo. That means that in this code, it is actually tried to allocate the memory and it indeed fails, hence we get the exception. Note that if we don't output, clang is still smart enough to even ignore the writes.
It appears that clang++ on Mac OSX does throw bad_alloc, but it also prints an error message from malloc.
Program:
// bad_alloc example
#include <iostream> // std::cout
#include <sstream>
#include <new> // std::bad_alloc
int main(int argc, char *argv[])
{
unsigned long long memSize = 10000;
if (argc < 2)
memSize = 10000;
else {
std::istringstream is(argv[1]); // C++ atoi
is >> memSize;
}
try
{
int* myarray= new int[memSize];
std::cout << "alloc of " << memSize << " succeeded" << std::endl;
}
catch (std::bad_alloc& ba)
{
std::cerr << "bad_alloc caught: " << ba.what() << '\n';
}
std::cerr << "Program exiting normally" << std::endl;
return 0;
}
Mac terminal output:
david@Godel:~/Dropbox/Projects/Miscellaneous$ badalloc
alloc of 10000 succeeded
Program exiting normally
david@Godel:~/Dropbox/Projects/Miscellaneous$ badalloc 1234567891234567890
badalloc(25154,0x7fff7622b310) malloc: *** mach_vm_map(size=4938271564938272768)
failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
bad_alloc caught: std::bad_alloc
Program exiting normally
I also tried the same program using g++ on Windows 7:
C:\Users\David\Dropbox\Projects\Miscellaneous>g++ -o badallocw badalloc.cpp
C:\Users\David\Dropbox\Projects\Miscellaneous>badallocw
alloc of 10000 succeeded
C:\Users\David\Dropbox\Projects\Miscellaneous>badallocw 1234567890
bad_alloc caught: std::bad_alloc
Note: The program is a modified version of the example at
http://www.cplusplus.com/reference/new/bad_alloc/