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

Erik Pilkington via cfe-dev cfe-dev at lists.llvm.org
Thu Jun 8 12:10:39 PDT 2017



On 6/8/17 11:36 AM, don hinton wrote:
> Thanks for the confirmation.  My solution was to use c_str().
I think you should prefer assigning from a std::string, using c_str() 
will force StringRef call strlen().
>
> 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 <mailto: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/compilerrt/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/libstdc++.so.6+0xc598a)
>>         #3 0x50d3bc in llvm::StringRef::str() const
>>     /home/d80049854/projects/clang/build/Debug/../../llvm/include/llvm/ADT/StringRef.h:230:14
>>         #4 0x50d2cd in llvm::StringRef::operator std::string() const
>>     /home/d80049854/projects/clang/build/Debug/../../llvm/include/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/clang/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/libstdc++.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/libstdc++.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 <mailto:cfe-dev at lists.llvm.org>
>>     http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>     <http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev>
>
>
>     _______________________________________________
>     cfe-dev mailing list
>     cfe-dev at lists.llvm.org <mailto:cfe-dev at lists.llvm.org>
>     http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>     <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/99f3b903/attachment.html>


More information about the cfe-dev mailing list