[cfe-dev] Is this a bug or just illegal code

Hubert Tong via cfe-dev cfe-dev at lists.llvm.org
Thu Jun 8 11:21:39 PDT 2017


On Thu, Jun 8, 2017 at 2:16 PM, Richard Smith <richard at metafoo.co.uk> wrote:

> On 8 June 2017 at 11:13, Hubert Tong via cfe-dev <cfe-dev at lists.llvm.org>
> wrote:
>
>> On Thu, Jun 8, 2017 at 2:05 PM, don hinton via cfe-dev <
>> cfe-dev at lists.llvm.org> wrote:
>>
>>> I'm seeing memory corruption when I use a literal string and std::string
>>> in a ternary (?:) expression.  If I change ss to ss.c_str() on line 5, the
>>> corruption goes away. [1] is an AST diff, which might help explain it.
>>>
>>> Although clang doesn't give me an error or warning, is this code legal,
>>> or is this a bug?
>>>
>>> thanks...
>>> don
>>>
>>>
>>> $ grep -n "." x.cpp
>>> 1:#include "llvm/ADT/StringRef.h"
>>> 3:int main() {
>>> 4:  const std::string ss;
>>> 5:  llvm::StringRef Ref = true ? "noexcept" : ss;
>>>
>> This creates a std::string temporary, leaving the StringRef pointing to
>> an object whose lifetime ends at the end of the full expression.
>> Maybe the StringRef interface can be adjusted to cause this to fail at
>> compile time.
>>
>
> It's a nice idea, but IIRC last time I tried this it didn't work out due
> to code like this relying on an implicit std::string -> StringRef
> conversion:
>
> std::string idiomatically_return_a_string();
> void idiomatically_take_a_string(StringRef);
>
> void f() {
>   idiomatically_take_a_string(idiomatically_return_a_string());
> }
>
Seems unfortunate that the g() and h() cases below are not very different
for overload resolution:
void f(llvm::StringRef);
void g() { f(std::string()); }
void h() { llvm::StringRef ref = std::string(); }


>
> 6:  std::string s = Ref;
>>> 7:  return 0;
>>> 8:}
>>>
>>> $ ../../4.0.0/build/Release/bin/clang++ x.cpp -O1 -g -fsanitize=address
>>> -fno-omit-frame-pointer -std=c++11 -I ../../llvm/include/ -I include
>>>
>>> $ ./a.out
>>> =================================================================
>>> ==14769==ERROR: AddressSanitizer: heap-use-after-free on address
>>> 0x604000000068 at pc 0x0000004651b2 bp 0x7ffcc5b3a7d0 sp 0x7ffcc5b39f80
>>> READ of size 8 at 0x604000000068 thread T0
>>>     #0 0x4651b1 in __interceptor_memcpy.part.36
>>> /home/d80049854/projects/clang/4.0.0/llvm/projects/compilerr
>>> t/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:655
>>>     #1 0x7f00fe4d10ed  (/usr/lib/x86_64-linux-gnu/li
>>> bstdc++.so.6+0xc40ed)
>>>     #2 0x7f00fe4d298a in std::basic_string<char, std::char_traits<char>,
>>> std::allocator<char> >::basic_string(char const*, unsigned long,
>>> std::allocator<char> const&) (/usr/lib/x86_64-linux-gnu/lib
>>> stdc++.so.6+0xc598a)
>>>     #3 0x50d3bc in llvm::StringRef::str() const
>>> /home/d80049854/projects/clang/build/Debug/../../llvm/includ
>>> e/llvm/ADT/StringRef.h:230:14
>>>     #4 0x50d2cd in llvm::StringRef::operator std::string() const
>>> /home/d80049854/projects/clang/build/Debug/../../llvm/includ
>>> e/llvm/ADT/StringRef.h:257:14
>>>     #5 0x50d0aa in main /home/d80049854/projects/clang
>>> /build/Debug/x.cpp:6:19
>>>     #6 0x7f00fd522f44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so
>>> .6+0x21f44)
>>>     #7 0x41a10b in _start (/home/d80049854/projects/clan
>>> g/build/Debug/a.out+0x41a10b)
>>>
>>> 0x604000000068 is located 24 bytes inside of 33-byte region
>>> [0x604000000050,0x604000000071)
>>> freed by thread T0 here:
>>>     #0 0x5098b0 in operator delete(void*) /home/d80049854/projects/clang
>>> /4.0.0/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:126
>>>     #1 0x7f00fe4d11cd in std::basic_string<char, std::char_traits<char>,
>>> std::allocator<char> >::~basic_string() (/usr/lib/x86_64-linux-gnu/lib
>>> stdc++.so.6+0xc41cd)
>>>     #2 0x7f00fd522f44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so
>>> .6+0x21f44)
>>>
>>> previously allocated by thread T0 here:
>>>     #0 0x508b70 in operator new(unsigned long)
>>> /home/d80049854/projects/clang/4.0.0/llvm/projects/compiler-
>>> rt/lib/asan/asan_new_delete.cc:82
>>>     #1 0x7f00fe4d0f68 in std::string::_Rep::_S_create(unsigned long,
>>> unsigned long, std::allocator<char> const&) (/usr/lib/x86_64-linux-gnu/lib
>>> stdc++.so.6+0xc3f68)
>>>
>>> SUMMARY: AddressSanitizer: heap-use-after-free
>>> /home/d80049854/projects/clang/4.0.0/llvm/projects/compiler-
>>> rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:655
>>> in __interceptor_memcpy.part.36
>>> Shadow bytes around the buggy address:
>>>   0x0c087fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>>>   0x0c087fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>>>   0x0c087fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>>>   0x0c087fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>>>   0x0c087fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>>> =>0x0c087fff8000: fa fa 00 00 00 00 00 01 fa fa fd fd fd[fd]fd fa
>>>   0x0c087fff8010: fa fa 00 00 00 00 01 fa fa fa fa fa fa fa fa fa
>>>   0x0c087fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
>>>   0x0c087fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
>>>   0x0c087fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
>>>   0x0c087fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
>>> Shadow byte legend (one shadow byte represents 8 application bytes):
>>>   Addressable:           00
>>>   Partially addressable: 01 02 03 04 05 06 07
>>>   Heap left redzone:       fa
>>>   Freed heap region:       fd
>>>   Stack left redzone:      f1
>>>   Stack mid redzone:       f2
>>>   Stack right redzone:     f3
>>>   Stack after return:      f5
>>>   Stack use after scope:   f8
>>>   Global redzone:          f9
>>>   Global init order:       f6
>>>   Poisoned by user:        f7
>>>   Container overflow:      fc
>>>   Array cookie:            ac
>>>   Intra object redzone:    bb
>>>   ASan internal:           fe
>>>   Left alloca redzone:     ca
>>>   Right alloca redzone:    cb
>>> ==14769==ABORTING
>>>
>>> 1. AST diff:
>>> < uses ss
>>> > uses ss.c_str()
>>>
>>> 49566c49566
>>> < | | |-CXXConstructorDecl 0xXXXXXXX <line:3010:7, col:XX> col:XX used
>>> basic_string 'void (const char *, const class std::allocator<char> &)'
>>> ---
>>> > | | |-CXXConstructorDecl 0xXXXXXXX <line:3010:7, col:XX> col:XX
>>> basic_string 'void (const char *, const class std::allocator<char> &)'
>>> 49568,49573c49568
>>> < | | | `-ParmVarDecl 0xXXXXXXX <col:XX, col:XX> col:XX __a 'const class
>>> std::allocator<char> &' cinit
>>> < | | |   `-ExprWithCleanups 0xXXXXXXX <col:XX, col:XX> 'const class
>>> std::allocator<char>':'const class std::allocator<char>' lvalue
>>> < | | |     `-MaterializeTemporaryExpr 0xXXXXXXX <col:XX, col:XX> 'const
>>> class std::allocator<char>':'const class std::allocator<char>' lvalue
>>> < | | |       `-ImplicitCastExpr 0xXXXXXXX <col:XX, col:XX> 'const class
>>> std::allocator<char>':'const class std::allocator<char>' <NoOp>
>>> < | | |         `-CXXBindTemporaryExpr 0xXXXXXXX <col:XX, col:XX> 'class
>>> std::allocator<char>':'class std::allocator<char>' (CXXTemporary 0xXXXXXXX)
>>> < | | |           `-CXXTemporaryObjectExpr 0xXXXXXXX <col:XX, col:XX>
>>> 'class std::allocator<char>':'class std::allocator<char>' 'void (void)
>>> throw()'
>>> ---
>>> > | | | `-ParmVarDecl 0xXXXXXXX <col:XX, col:XX> col:XX __a 'const class
>>> std::allocator<char> &'
>>> 108945c108940
>>> < | | |-CXXConstructorDecl 0xXXXXXXX <../../llvm/include/llvm/Support/Compiler.h:194:38,
>>> ../../llvm/include/llvm/ADT/StringRef.h:96:49> line:95:18 used
>>> StringRef 'void (const std::string &)'
>>> ---
>>> > | | |-CXXConstructorDecl 0xXXXXXXX <../../llvm/include/llvm/Support/Compiler.h:194:38,
>>> ../../llvm/include/llvm/ADT/StringRef.h:96:49> line:95:18 StringRef
>>> 'void (const std::string &)'
>>> 111747,111765c111742,111749
>>> <     |           `-CXXConstructExpr 0xXXXXXXX <col:XX, col:XX>
>>> 'llvm::StringRef':'class llvm::StringRef' 'void (const std::string &)'
>>> <     |             `-MaterializeTemporaryExpr 0xXXXXXXX <col:XX,
>>> col:XX> 'const std::string':'const class std::basic_string<char>' lvalue
>>> <     |               `-ConditionalOperator 0xXXXXXXX <col:XX, col:XX>
>>> 'const std::string':'const class std::basic_string<char>'
>>> <     |                 |-CXXBoolLiteralExpr 0xXXXXXXX <col:XX> '_Bool'
>>> true
>>> <     |                 |-CXXBindTemporaryExpr 0xXXXXXXX <col:XX> 'const
>>> std::string':'const class std::basic_string<char>' (CXXTemporary 0xXXXXXXX)
>>> <     |                 | `-CXXConstructExpr 0xXXXXXXX <col:XX> 'const
>>> std::string':'const class std::basic_string<char>' 'void (const class
>>> std::basic_string<char> &)' elidable
>>> <     |                 |   `-MaterializeTemporaryExpr 0xXXXXXXX
>>> <col:XX> 'const std::string':'const class std::basic_string<char>' lvalue
>>> <     |                 |     `-CXXBindTemporaryExpr 0xXXXXXXX <col:XX>
>>> 'const std::string':'const class std::basic_string<char>' (CXXTemporary
>>> 0xXXXXXXX)
>>> <     |                 |       `-CXXConstructExpr 0xXXXXXXX <col:XX>
>>> 'const std::string':'const class std::basic_string<char>' 'void (class
>>> std::basic_string<char> &&) noexcept' elidable
>>> <     |                 |         `-MaterializeTemporaryExpr 0xXXXXXXX
>>> <col:XX> 'std::string':'class std::basic_string<char>' xvalue
>>> <     |                 |           `-CXXBindTemporaryExpr 0xXXXXXXX
>>> <col:XX> 'std::string':'class std::basic_string<char>' (CXXTemporary
>>> 0xXXXXXXX)
>>> <     |                 |             `-ImplicitCastExpr 0xXXXXXXX
>>> <col:XX> 'std::string':'class std::basic_string<char>'
>>> <ConstructorConversion>
>>> <     |                 |               `-CXXConstructExpr 0xXXXXXXX
>>> <col:XX> 'std::string':'class std::basic_string<char>' 'void (const char *,
>>> const class std::allocator<char> &)'
>>> <     |                 |                 |-ImplicitCastExpr 0xXXXXXXX
>>> <col:XX> 'const char *' <ArrayToPointerDecay>
>>> <     |                 |                 | `-StringLiteral 0xXXXXXXX
>>> <col:XX> 'const char [9]' lvalue "noexcept"
>>> <     |                 |                 `-CXXDefaultArgExpr 0xXXXXXXX
>>> <<invalid sloc>> 'const class std::allocator<char>':'const class
>>> std::allocator<char>' lvalue
>>> <     |                 `-CXXBindTemporaryExpr 0xXXXXXXX <col:XX> 'const
>>> std::string':'const class std::basic_string<char>' (CXXTemporary 0xXXXXXXX)
>>> <     |                   `-CXXConstructExpr 0xXXXXXXX <col:XX> 'const
>>> std::string':'const class std::basic_string<char>' 'void (const class
>>> std::basic_string<char> &)'
>>> <     |                     `-DeclRefExpr 0xXXXXXXX <col:XX> 'const
>>> std::string':'const class std::basic_string<char>' lvalue Var 0xXXXXXXX
>>> 'ss' 'const std::string':'const class std::basic_string<char>'
>>> ---
>>> >     |           `-CXXConstructExpr 0xXXXXXXX <col:XX, col:XX>
>>> 'llvm::StringRef':'class llvm::StringRef' 'void (const char *)'
>>> >     |             `-ConditionalOperator 0xXXXXXXX <col:XX, col:XX>
>>> 'const char *'
>>> >     |               |-CXXBoolLiteralExpr 0xXXXXXXX <col:XX> '_Bool'
>>> true
>>> >     |               |-ImplicitCastExpr 0xXXXXXXX <col:XX> 'const char
>>> *' <ArrayToPointerDecay>
>>> >     |               | `-StringLiteral 0xXXXXXXX <col:XX> 'const char
>>> [9]' lvalue "noexcept"
>>> >     |               `-CXXMemberCallExpr 0xXXXXXXX <col:XX, col:XX>
>>> 'const char *'
>>> >     |                 `-MemberExpr 0xXXXXXXX <col:XX, col:XX> '<bound
>>> member function type>' .c_str 0xXXXXXXX
>>> >     |                   `-DeclRefExpr 0xXXXXXXX <col:XX> 'const
>>> std::string':'const class std::basic_string<char>' lvalue Var 0xXXXXXXX
>>> 'ss' 'const std::string':'const class std::basic_string<char>'
>>>
>>> _______________________________________________
>>> cfe-dev mailing list
>>> cfe-dev at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>>
>>>
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170608/b7b1fe3f/attachment.html>


More information about the cfe-dev mailing list