[RFC] Exception-friendly ASan annotations of std::string

Ivan Baravy i.baravy@samsung.com
Tue Jun 13 11:15:00 GMT 2017



On 06/12/2017 01:13 PM, Jonathan Wakely wrote:
> On 12/06/17 11:11 +0100, Jonathan Wakely wrote:
>> On 09/06/17 23:43 +0300, Ivan Baravy wrote:
>>> Hello,
>>>
>>> I'm working on address sanitization of standard containers. The aim is
>>> to detect and report accesses between size and capacity. The issue I
>>> faced is related to std::length_error and std::bad_alloc exceptions. I
>>> can get std::bad_alloc via huge fill insert into std::string. ASan adds
>>> a memory overhead (internal structures) to user allocations and, when
>>> enabled, it intercepts memory-related functions, failed allocations of
>>> vital structures make it terminate the process. Thus it looks like
>>> pointless for ASan annotations to be friendly to std::length_error and
>>> std::bad_alloc exceptions.
>>>
>>> So my question is if it's acceptable to not consider std::length_error
>>> and std::bad_alloc in address sanitization design?
>>
>> I'm not sure if I understand the question, sorry.
>>
>> ASan makes failed allocations call terminate, so you'll never get
>> std::bad_alloc from operator new, is that right?

Exactly, sorry if I was unclear about that.
>> And you could still std::get bad_alloc from custom allocators, for
>> example the following throws std::bad_alloc without ever attempting to
>> allocate memory using operator new, or malloc:
>>
>> #include <string>
>> #include <memory>
>>
>> char buf[1024];
>> char* last = buf;
>>
>> template<class T>
>> struct Alloc {
>> using value_type = T;
>> Alloc() { }
>> template<typename U> Alloc(const Alloc<U>&) { }
>>
>> T* allocate(std::size_t n) {
>>   void* p = last;
>>   if (std::size_t(-1) / sizeof(T) > n)
>>     throw std::bad_alloc();
>>   n *= sizeof(T);
>>   std::size_t space = 1024 - (last - buf);
>>   if (!std::align(alignof(T), n, p, space))
>>     throw std::bad_alloc();
>>   last = (char*)p + n;
>>   return (T*)p;
>> }
>>
>> void deallocate(T* p, std::size_t n) {
>>   n *= sizeof(T);
>>   char* pc = (char*)p;
>>   if (last == pc + n)
>>     last = pc;
>> }
>>
>> template<typename U> bool operator==(Alloc<U>) const { return true; }
>> template<typename U> bool operator!=(Alloc<U>) const { return false; }
>> };
>>
>> int main()
>> {
>> std::basic_string<char, std::char_traits<char>, Alloc<char>> s(1025, 'a');
>> }

ASan makes some assumptions on allocator's behavior (e.g. alignment).
Therefore I follow design of ASan annotations in libc++ and enable
sanitizer checks for std::allocator only. Perhaps, If I write a custom
allocator that will meet requirements of ASan and throw bad_alloc or
length_error 'by request', then I can test my implementation easily.
Thank you for hints to this idea.

>> But what does that have to do with std::length_error?
>>
> 
> If you're *only* talking about std::string and not other
> specializations of std::basic_string, then I agree that you won't get
> std::bad_alloc if ASan always terminates the process. But you can
> still get std::length_error.

Yes, I talk about std::string only, at least for now. I've been
rethinking this last days and now agree that std::length_error is still
to be considered. It seems I wanted a small, fast but wrong design.

Thank you for your comments and time, Jonathan.

Regards,
Ivan



More information about the Libstdc++ mailing list