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

don hinton via cfe-dev cfe-dev at lists.llvm.org
Thu Jun 8 11:36:05 PDT 2017


Thanks for the confirmation.  My solution was to use c_str().

I wish there was a way for clang to warn about this, but as you mentioned,
it's difficult to know what StringRef will do with the result.

thanks again...
don

On Thu, Jun 8, 2017 at 11:16 AM, Erik Pilkington via cfe-dev <
cfe-dev at lists.llvm.org> wrote:

>
>
> On 6/8/17 11:05 AM, don hinton via cfe-dev 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?
>
> No, this is a bug in x.cpp. the common type between "noexcept" and
> std::string is std::string, which means that the conditional expression
> materializes a temporary string to hold the "noexcept" and binds it to the
> StringRef when the true branch is taken. Clang doesn't warn here because it
> isn't smart enough to know what StringRef is doing. You can try rewriting
> this as:
>
> llvm::StringRef Ref = "noexcept";
> if (true || whatever)
>   Ref = some_std_string;
>
>
> 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;
> 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/libstdc++.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 listcfe-dev at lists.llvm.orghttp://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/fa72ac03/attachment.html>


More information about the cfe-dev mailing list