[cxx-abi-dev] Run-time array checking

Mike Herrick mjh at edg.com
Thu Sep 6 20:31:17 UTC 2012


On Sep 6, 2012, at 1:52 PM, John McCall wrote:

> On Sep 6, 2012, at 5:46 AM, Mike Herrick wrote:
>> Here are some basic strategies for doing the run-time checking:
>> 
>> 1) Have the compiler generate inline code to do the bounds checking before calling the existing runtime routines.  The problem with this is that there is no IA-64 ABI standard way to throw a std::bad_array_new_length exception once a violation has been detected (so we'd need to add something like __cxa_throw_bad_array_new_length).
> 
> Having such a function is a good idea anyway, because you can't always use one of the vec helpers, e.g. if the allocation function takes placement args.

Good point (though if we went with option 3 below it wouldn't be needed, but option 2 does not provide a complete solution).

> 
> For what it's worth, clang has always done this overflow checking (counting negative counts as an overflow in the signed->unsigned computation), although we don't reliably cause the right exception to be thrown — we simply pass (size_t) -1 to the allocation function.  Unfortunately, I think that's pretty obviously wrong under the standard, which seems to make it clear that we're not supposed to be calling the allocation function at all in this case.
> 
>> 2) Have the runtime libraries do the checking and throw std::bad_array_new_length as needed.  In order to do this (in a backwards compatible way) I think we'd need to add new versions of __cxa_vec_new2/__cxa_vec_new3 where the element_count is signed and the number of initializers in the array is passed as a new argument.
> 
> Well, if we can use (size_t) -1 as a signal value, we don't need any new entrypoints.  That would be safe on any platform where there are values of size_t which cannot possibly be allocated;  of course, that property of size_t isn't guaranteed by the standard, although it's universally true these days, I think.
> 
> Don't get me wrong, adding new entrypoints is definitely cleaner.  The main problem with adding and using new entrypoints is that it means that old, C++98-compliant code being recompiled will suddenly require new things from the runtime, which introduces deployment problems.  And these problems are arguably inherent.   std::bad_array_new_length doesn't even exist in a C++98 standard library, so it's not like we can just emit our own copy of __cxa_throw_bad_array_new_length when we're not sure it exists;  we'd potentially have to emit the class itself, which has all sorts of nasty problems (e.g. because the RTTI is almost certainly a strong symbol in the stdlib's shared library).  So in practice we're talking about emitting this code only if it's known that the deployment target can handle it;  this is is okay for me, because clang has a relatively rich deployment-target model, but I wanted to raise the point.

One approach around the lack of std::bad_array_new_length could be to have __cxa_throw_bad_array_new_length throw std::bad_alloc as a stopgap solution.

> 
>> 3) A new routine, say __cxa_vec_new_check, that takes a signed element_count, element_size, and number of initialized elements and does all necessary checks, throwing std::bad_array_new_length if required, otherwise returning.
> 
> It would also need to know how much cookie to add.  The cookie causing an overflow would certainly be an example of "the value of that expression is ... such that the size of the allocated object would exceed the implementation-defined limit".

Agreed; padding_size should be an argument if we go this way.

Mike.



More information about the cxx-abi-dev mailing list