<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Porting my <font face="Courier" class="">std::function</font> <a href="https://github.com/potswa/cxx_function/" class="">library</a> to MSVC, some UB reared its head. The function wrapper class uses an <font face="Courier" class="">aligned_storage</font> blob for its call target under the small-object optimization. When the target is small and trivially-copyable, the copy/move constructors use <font face="Courier" class="">memcpy</font> on the blob to avoid determining the dynamic type of the target.<div class=""><br class=""></div><div class="">MSVC seems to do stricter alias analysis than GCC or Clang. The effect of the <font face="Courier" class="">memcpy</font> is not subsequently observed unless its both its source and destination operands are of the appropriate type (before they’re implicitly cast to <font face="Courier" class="">void*</font>).</div><div class=""><br class=""></div><div class=""><div class=""><font face="Courier" class="">// Given:</font></div><div class=""><font face="Courier" class="">erasure_base & erasure()</font></div><div class=""><font face="Courier" class=""> { return reinterpret_cast< erasure_base & >( this->storage ); }</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">// Inside copy/move constructor:</font></div><div class=""><span style="font-family: Courier;" class="">// (1) well-behaved:</span></div><div class=""><font face="Courier" class="">std::memcpy( & erasure(), & o.erasure(), sizeof (storage) );</font></div></div><div class=""><font face="Courier" class="">// (2) crashes after erasure().foo observes stale bytes:</font></div><div class=""><font face="Courier" class="">std::memcpy( & erasure(), & storage, sizeof (storage) );</font></div><div class=""><br class=""></div><div class="">In retrospect, (1) is certainly more kosher, but shouldn’t (2) work as well?</div><div class=""><br class=""></div><div class="">This doesn’t seem to rise to the level of a bug report, but it might be relevant to the new <font face="Courier" class="">memcpy</font> lifetime-initiation rules. Will they ascribe some static type to the source and destination bytes?</div><div class=""><br class=""></div><div class="">More worryingly, <font face="Courier" class="">erasure_base</font> is a base class. When the <font face="Courier" class="">memcpy</font> replaces one derived object with another of the same type, what’s the guarantee that the overwritten value won’t be observed? This problem doesn’t manifest so far, but it seems only a matter of time. No easy solution comes to mind, nor any practical workaround for type-erasure libraries. The tough solution is for alias analysis to somehow work without considering the static types passed to <font face="Courier" class="">memcpy</font>.</div><div class=""><br class=""></div><div class="">I’m no expert on alias analysis, so I don’t know whether GCC and Clang are more clever, or less aggressive. Is it luck that the same bug hasn’t appeared on other platforms? Any insights about the upcoming rules?</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>- thanks,</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>D</div><div class=""><br class=""></div></body></html>