[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