<div dir="ltr"><div><div>My two cents: even when memcpy becomes capable of initiating the lifetime of (and initializing) an object in an &quot;aligned_storage blob&quot;, the kosher way of accessing that object would require std::launder.<br><br></div>Now, I am not sure if it is a copy/paste error, my misunderstanding of the code, or what, but it seems that (2) crashes because &quot;&amp;erasure()&quot; and &quot;&amp;storage&quot; overlap (and if the memcpy UB was not enough, it probably does not do what you intended).<br><br></div>-- HT<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Jan 8, 2016 at 10:15 AM, David Krauss <span dir="ltr">&lt;<a href="mailto:david_work@me.com" target="_blank">david_work@me.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">Porting my <font face="Courier">std::function</font> <a href="https://github.com/potswa/cxx_function/" target="_blank">library</a> to MSVC, some UB reared its head. The function wrapper class uses an <font face="Courier">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">memcpy</font> on the blob to avoid determining the dynamic type of the target.<div><br></div><div>MSVC seems to do stricter alias analysis than GCC or Clang. The effect of the <font face="Courier">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">void*</font>).</div><div><br></div><div><div><font face="Courier">// Given:</font></div><div><font face="Courier">erasure_base &amp; erasure()</font></div><div><font face="Courier">    { return reinterpret_cast&lt; erasure_base &amp; &gt;( this-&gt;storage ); }</font></div><div><font face="Courier"><br></font></div><div><font face="Courier">// Inside copy/move constructor:</font></div><div><span style="font-family:Courier">// (1) well-behaved:</span></div><div><font face="Courier">std::memcpy( &amp; erasure(), &amp; o.erasure(), sizeof (storage) );</font></div></div><div><font face="Courier">// (2) crashes after erasure().foo observes stale bytes:</font></div><div><font face="Courier">std::memcpy( &amp; erasure(), &amp; storage, sizeof (storage) );</font></div><div><br></div><div>In retrospect, (1) is certainly more kosher, but shouldn’t (2) work as well?</div><div><br></div><div>This doesn’t seem to rise to the level of a bug report, but it might be relevant to the new <font face="Courier">memcpy</font> lifetime-initiation rules. Will they ascribe some static type to the source and destination bytes?</div><div><br></div><div>More worryingly, <font face="Courier">erasure_base</font> is a base class. When the <font face="Courier">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">memcpy</font>.</div><div><br></div><div>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><br></div><div><span style="white-space:pre-wrap">        </span>- thanks,</div><div><span style="white-space:pre-wrap">        </span>D</div><div><br></div></div><br>_______________________________________________<br>
ub mailing list<br>
<a href="mailto:ub@isocpp.open-std.org">ub@isocpp.open-std.org</a><br>
<a href="http://www.open-std.org/mailman/listinfo/ub" rel="noreferrer" target="_blank">http://www.open-std.org/mailman/listinfo/ub</a><br>
<br></blockquote></div><br></div>