<html>
    <head>
      <base href="https://llvm.org/bugs/" />
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW --- - Overlapping memcpy in SmallVector.h (via SmallString::operator=())"
   href="https://llvm.org/bugs/show_bug.cgi?id=25293">25293</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Overlapping memcpy in SmallVector.h (via SmallString::operator=())
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Support Libraries
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>mattipee@yahoo.co.uk
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr>

        <tr>
          <th>Classification</th>
          <td>Unclassified
          </td>
        </tr></table>
      <p>
        <div>
        <pre>clang version 3.8.0 (<a href="http://llvm.org/git/clang.git">http://llvm.org/git/clang.git</a>
3a551363c4cdd54c939cd9cc969d45bc8f8e93d8) (<a href="http://llvm.org/git/llvm.git">http://llvm.org/git/llvm.git</a>
ca4c86d2fd31ba4c23b9f3028e4f812713f230c6)
Target: x86_64-unknown-linux-gnu
Thread model: posix

==26255== Memcheck, a memory error detector
==26255== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==26255== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright
info
==26255== Command: clang++ --std=c++14 -I/usr/local/include -E -o
/tmp/56294cc2_0xffefffa30/testcase.ii /tmp/56294cc2_0xffefffa30/testcase.cpp
==26255== 
==26255== Source and destination overlap in memcpy(0xffeffe7c0, 0xffeffe7c0,
42)
==26255==    at 0x6D140CD: memcpy@@GLIBC_2.14 (vg_replace_strmem.c:1018)
==26255==    by 0x9E5724:
_ZN4llvm23SmallVectorTemplateBaseIcLb1EE18uninitialized_copyIKccEEvPT_S5_PT0_PNSt9enable_ifIXsr3std7is_sameINSt12remove_constIS4_E4typeES6_EE5valueEvE4typeE
(SmallVector.h:328)
==26255==    by 0x9E55AA: void llvm::SmallVectorImpl<char>::append<char
const*>(char const*, char const*) (SmallVector.h:430)
==26255==    by 0x9E586F: void llvm::SmallString<128u>::append<char
const*>(char const*, char const*) (SmallString.h:75)
==26255==    by 0x9E5824: llvm::SmallString<128u>::operator+=(llvm::StringRef)
(SmallString.h:286)
==26255==    by 0x9E5247: llvm::SmallString<128u>::operator=(llvm::StringRef)
(in /.../build-debug/bin/clang-3.8)
==26255==    by 0x9DE90D: SetInstallDir(llvm::SmallVectorImpl<char const*>&,
clang::driver::Driver&, bool) (driver.cpp:293)
==26255==    by 0x9DD74A: main (driver.cpp:435)


Suggested change:

diff --git a/include/llvm/ADT/SmallVector.h b/include/llvm/ADT/SmallVector.h
index d1062ac..d6f13f3 100644
--- a/include/llvm/ADT/SmallVector.h
+++ b/include/llvm/ADT/SmallVector.h
@@ -324,7 +324,7 @@ protected:
     // iterators): std::uninitialized_copy optimizes to memmove, but we can
     // use memcpy here. Note that I and E are iterators and thus might be
     // invalid for memcpy if they are equal.
-    if (I != E)
+    if (I != E && I != Dest)
       memcpy(Dest, I, (E - I) * sizeof(T));
   }


Looking further, I guess it's ok for SmallString to clear() the underlying
SmallVector in the assignment operator. Even though the "StringRef RHS"
returned by parent_path still points into the data being cleared, it's not
going to go anywhere as a parent path is always going to be shorter. Either
way, the overlapping memcpy could be avoided as above.


driver.cpp:293

  InstalledPath = llvm::sys::path::parent_path(InstalledPath);



SmallString.h:280-288

  const SmallString &operator=(StringRef RHS) {
    this->clear();
    return *this += RHS;
  }

  SmallString &operator+=(StringRef RHS) {
    this->append(RHS.begin(), RHS.end());
    return *this;
  }</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>