<div dir="ltr">I know it is. I just hope it stays hidden deep where those who know about it are... essentially those who read this mailing list :)<br></div><div class="gmail_extra"><br><div class="gmail_quote">2016-01-09 16:42 GMT-05:00 Gabriel Dos Reis <span dir="ltr"><<a href="mailto:gdr@microsoft.com" target="_blank">gdr@microsoft.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div link="blue" vlink="purple" lang="EN-US">
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:#1f497d">My assumption has always been that std::launder is a zero-overhead abstraction (really a no-op at the machine level) whole sole purpose is to inform the static
semantics elaborator about the lifetime and type of a given storage. I hope we aren’t considering anything more complicated than that.<u></u><u></u></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:#1f497d"><u></u> <u></u></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:#1f497d">-- Gaby<u></u><u></u></span></p>
<p class="MsoNormal"><a name="918590690__MailEndCompose"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:#1f497d"><u></u> <u></u></span></a></p>
<div style="border:none;border-left:solid blue 1.5pt;padding:0in 0in 0in 4.0pt">
<div>
<div style="border:none;border-top:solid #e1e1e1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b><span style="font-size:11.0pt;font-family:"Calibri",sans-serif">From:</span></b><span style="font-size:11.0pt;font-family:"Calibri",sans-serif"> <a href="mailto:ub-bounces@open-std.org" target="_blank">ub-bounces@open-std.org</a> [mailto:<a href="mailto:ub-bounces@open-std.org" target="_blank">ub-bounces@open-std.org</a>]
<b>On Behalf Of </b>David Krauss<br>
<b>Sent:</b> Friday, January 8, 2016 10:36 PM<span class=""><br>
<b>To:</b> WG21 UB study group <<a href="mailto:ub@open-std.org" target="_blank">ub@open-std.org</a>><br>
</span><b>Cc:</b> <a href="mailto:joel.lamotte@gmail.com" target="_blank">joel.lamotte@gmail.com</a><span class=""><br>
<b>Subject:</b> Re: [ub] memcpy blessing a new object of statically unknown type<u></u><u></u></span></span></p>
</div>
</div>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<p class="MsoNormal">On 2016–01–09, at 11:35 AM, Hubert Tong <<a href="mailto:hubert.reinterpretcast@gmail.com" target="_blank">hubert.reinterpretcast@gmail.com</a>> wrote:<u></u><u></u></p>
</div><div><div class="h5">
<p class="MsoNormal"><u></u> <u></u></p>
<div>
<p class="MsoNormal"><span style="font-size:9.0pt;font-family:"Helvetica",sans-serif">Yes,<span> </span></span><span style="font-size:9.0pt;font-family:"Courier New"">std::launder</span><span><span style="font-size:9.0pt;font-family:"Helvetica",sans-serif"> </span></span><span style="font-size:9.0pt;font-family:"Helvetica",sans-serif">requires
a static type; however, it does not limit the ability of<span> </span></span><span style="font-size:9.0pt;font-family:"Courier New"">memcpy</span><span><span style="font-size:9.0pt;font-family:"Helvetica",sans-serif"> </span></span><span style="font-size:9.0pt;font-family:"Helvetica",sans-serif">to
operate without knowing the type of the object being copied. The<span> </span></span><span style="font-size:9.0pt;font-family:"Courier New"">std::launder</span><span><span style="font-size:9.0pt;font-family:"Helvetica",sans-serif"> </span></span><span style="font-size:9.0pt;font-family:"Helvetica",sans-serif">call
is involved<span> </span><i>after</i><span> </span>the completion of<span> </span></span><span style="font-size:9.0pt;font-family:"Courier New"">memcpy</span><span><span style="font-size:9.0pt;font-family:"Helvetica",sans-serif"> </span></span><span style="font-size:9.0pt;font-family:"Helvetica",sans-serif">to
access the object that the<span> </span></span><span style="font-size:9.0pt;font-family:"Courier New"">memcpy</span><span style="font-size:9.0pt;font-family:"Helvetica",sans-serif">initialized.</span><u></u><u></u></p>
</div>
</div></div></blockquote>
</div><div><div class="h5">
<p class="MsoNormal"><u></u> <u></u></p>
<div>
<p class="MsoNormal">Right, but in type erasure, the static type must be determined by inspecting the blob somehow. (Stashing a discriminating value elsewhere is one solution, but it’s more common and often more efficient to use an abstract base class or a
discriminator inside a union.)<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal">My library would launder the <span style="font-family:Courier">
erasure_base</span> subobject to retrieve its dispatch table, but then it’d be stuck. Dispatching to a derived class would lead back to UB.<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><u></u> <u></u></p>
</div>
<div>
<div>
<p class="MsoNormal">One workaround could be to launder the same address repeatedly as the type becomes better resolved. For example, the call wrapper could launder a base class address, then perform an indirect call, then the callee could launder again to
the derived class. For the common case of virtual dynamic dispatch, this sounds like it would incur UB before first line of the callee. My library doesn’t use <span style="font-family:Courier">virtual</span>, but similar ones do. If only complete objects can
be laundered, devirtualization could kick in… or launder could refuse to handle an abstract class at all. The workaround would also imply an excessive number of derived-type <span style="font-family:Courier">launder</span> calls, which could compromise optimization
by suggesting that bitwise manipulations are occurring when none are. Reloading the dispatch table pointer costs cycles.<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal">Perhaps a second style of laundering could implement a compromise. First, <span style="font-family:Courier">auto &header = *launder(header_ptr)</span> gets a fully-formed <span style="font-family:Courier">header</span> object from a blob,
and then <span style="font-family:Courier">auto &whole = launder_extend<whole_type>(header)</span> revises the object identity to make <span style="font-family:Courier">header</span> a subobject sharing its address with another already-fully-formed object
of type <span style="font-family:Courier">whole</span>. (For example, <span style="font-family:Courier">header</span> could be a base, a <span style="font-family:Courier">union</span> member, or an initial <span style="font-family:Courier">struct</span> member.)
The <span style="font-family:Courier">launder_extend</span> function differs in that it acts only if its argument was believed to be a complete object (i.e. fresh from <span style="font-family:Courier">launder</span>), and it only launders the remainder of
the new complete object. To solve the <span style="font-family:Courier">virtual</span> issue, do not let <span style="font-family:Courier">launder</span> imply that its result is most-derived. Perhaps, let virtual dispatch implicitly do <span style="font-family:Courier">launder_extend</span>.<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal">This scheme leaves <span style="font-family:Courier">launder</span> open-ended so a polymorphic object or union can be used, yet still laundered further. A simple implementation can opt to treat
<span style="font-family:Courier">launder_extend</span> the same as <span style="font-family:Courier">
launder</span>.<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal">Example:<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier">struct discriminator { int value; };</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier">struct foo { discriminator d; int i; };</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier">struct bar { discriminator d; float f; };</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier">union foobar { foo a; bar b; };</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier">struct baz : discriminator { double x; };</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier">struct bad : discriminator { virtual ~ bad(); };</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier">void unpack( discriminator * p ) {</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> std::launder( p ); // OK: now we can access p.</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> int disc = p->value;</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> if ( disc == 0 ) {</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> auto & f = std::launder_extend< foo >( * p ); // OK: now we can access a foo.</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> int q = p->value; // Load may be elided. Value is already in disc, equal to zero.</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> auto & fb = std::launder_extend< foobar >( * f ); // OK: a further extension to a super-object.</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> auto & f2 = std::launder_extend< foo >( * p ); // OK, no-op: p was already extended, becoming a subobject.</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> auto & b = std::launder_extend< bar >( * p ); // UB: there’s already a different object there.</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> auto & i = std::launder_extend< int >( * p ); // Library precondition violation: invalid object extension.</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> } else if ( disc == 1 ) {</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> baz & z = std::launder_extend< baz >( * p ); // OK, but implementation-dependent in theory.</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> } else if ( disc == 2 ) {</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> // Library precondition violation: no discriminator subobject shares an address with class bad.</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> bad & x = std::launder_extend< bad >( * p );</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier"> }</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><span style="font-family:Courier">}</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal"><u></u> <u></u></p>
</div>
</div>
</div></div></div>
</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>