[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:13:06 PDT 2017


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.


> 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 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/82e27e96/attachment.html>


More information about the cfe-dev mailing list