<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:12.0pt;
        font-family:"Times New Roman","serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
span.EmailStyle17
        {mso-style-type:personal-reply;
        font-family:"Calibri","sans-serif";
        color:#1F497D;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri","sans-serif";}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">For the first example: I’d be inclined to view it as type-unsafe because of the cast from void* to B*, not because of the malloc.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">For the rest: At quick glance, the my_malloc/my_free internals look type safe to me, so the issue isn’t wrapping malloc/free per se. Rather, it’s the calling
 code that’s unsafe for casting from void* to B*, which is unchanged in the optimized version of the code.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">So IMO the three examples are all the same because they all contain the unsafe cast from void* to B*, just moving it around a little.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Moving to a question you didn’t ask: What if my_malloc/my_free returned/took not void*, but my_class* (so a class-specific allocator, implemented using malloc/free)?
 That is:<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span style="font-family:&quot;Courier New&quot;">std::map&lt;size_t, std::stack&lt;my_class*&gt;&gt; size_classes = {{16, {}}, {32, {}}, ...};<br>
<br>
my_class* my_malloc(size_t size) {<br>
&nbsp; auto size_class = size_classes.lower_bound(size);<br>
&nbsp; assert(size_class != size_classes.end());<br>
&nbsp; if (size_class-&gt;second.empty())<br>
&nbsp; &nbsp; return (my_class*)malloc(size_class-&gt;first);<br>
&nbsp; void* result = size_class-&gt;second.top();<br>
&nbsp; size_class-&gt;second.pop();<br>
&nbsp; return result;<br>
}<br>
<br>
void my_free(size_t size, my_class* block) {<br>
&nbsp; size_classes.lower_bound(size)-&gt;second.push(block);<br>
}</span><br>
<br>
<span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Then this would require some decoration around the (single) cast to my_class*, perhaps:<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span style="font-family:&quot;Courier New&quot;">&nbsp; ...<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family:&quot;Courier New&quot;">&nbsp; if (size_class-&gt;second.empty()) {<br>
&nbsp; &nbsp; my_class* ret = nullptr;<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family:&quot;Courier New&quot;">&nbsp;&nbsp;&nbsp; extern “c-style” {<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family:&quot;Courier New&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = (my_class*)malloc(size_class-&gt;first);<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family:&quot;Courier New&quot;">&nbsp;&nbsp;&nbsp; }<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family:&quot;Courier New&quot;">&nbsp;&nbsp;&nbsp; return ret;<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family:&quot;Courier New&quot;">&nbsp; }<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family:&quot;Courier New&quot;">&nbsp; …<br>
<br>
</span><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">And this doesn’t surprise me because I would expect the internals of an allocator to be a classic example of code that resorts to the explicit type-unsafe escape
 hatch (“extern “C-style” { }” block around or whatever).<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Herb<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><a name="_MailEndCompose"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"><o:p>&nbsp;</o:p></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:&quot;Calibri&quot;,&quot;sans-serif&quot;">From:</span></b><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;"> ub-bounces@open-std.org [mailto:ub-bounces@open-std.org]
<b>On Behalf Of </b>Jeffrey Yasskin<br>
<b>Sent:</b> Friday, January 17, 2014 4:21 PM<br>
<b>To:</b> WG21 UB study group<br>
<b>Subject:</b> Re: [ub] type punning through congruent base class?<o:p></o:p></span></p>
</div>
</div>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<div>
<p class="MsoNormal">I'd like to complicate things further, in response to the idea that the snippet involving 'B' and 'short' is type-punning and that we should consider a type-safe mode. :)<br>
<br>
First, consider whether the following code, intended to be completely normal C code:<br>
<br>
<span style="font-family:&quot;Courier New&quot;">&nbsp; B* pb = (B*)malloc(sizeof(B));<br>
&nbsp; pb-&gt;i = 0;<br>
&nbsp; free(pb);<br>
&nbsp; short* ps = (short*)malloc(sizeof(short));<br>
&nbsp; *ps = 0;<br>
&nbsp; free(ps);</span><br>
<br>
looks like code that should be valid in this type-safe mode. If you'd like to ban it, the rest of this post won't have anything interesting for you.<br>
<br>
Now imagine I write a library (please forgive compile and logic errors, and typos):<br>
<br>
<span style="font-family:&quot;Courier New&quot;">std::map&lt;size_t, std::stack&lt;void*&gt;&gt; size_classes = {{16, {}}, {32, {}}, ...};<br>
<br>
void* my_malloc(size_t size) {<br>
&nbsp; auto size_class = size_classes.lower_bound(size);<br>
&nbsp; assert(size_class != size_classes.end());<br>
&nbsp; if (size_class-&gt;second.empty())<br>
&nbsp; &nbsp; return malloc(size_class-&gt;first);<br>
&nbsp; void* result = size_class-&gt;second.top();<br>
&nbsp; size_class-&gt;second.pop();<br>
&nbsp; return result;<br>
}<br>
<br>
void my_free(size_t size, void* block) {<br>
&nbsp; size_classes.lower_bound(size)-&gt;second.push(block);<br>
}</span><br>
<br>
Then I use it like:<br>
<br>
<span style="font-family:&quot;Courier New&quot;">&nbsp; B* pb = (B*)my_malloc(sizeof(B));<br>
&nbsp; pb-&gt;i = 0;<br>
&nbsp; my_free(sizeof(B), pb);<br>
&nbsp; short* ps = (short*)my_malloc(sizeof(short));<br>
&nbsp; *ps = 0;<br>
&nbsp; my_free(sizeof(short), ps);</span><br>
<br>
Is this worse than the above malloc/free-based code? That is, can users write wrappers around malloc and free?<br>
<br>
But the compiler can inline the my_malloc use down to:<br>
<br>
<span style="font-family:&quot;Courier New&quot;">&nbsp; void *p = malloc(16); &nbsp;// Probably 16.<br>
&nbsp; B* pb = (B*)p;<br>
&nbsp; pb-&gt;i = 0;<br>
&nbsp; short* ps = (short*)pb;<br>
&nbsp; *ps = 0;</span><br>
<br>
using knowledge of the behavior of std::map and std::stack, which is nearly identical to the &quot;type-punning&quot; code. So how do we make the type-punning invalid without breaking standard malloc-based code or user-written libraries?<br>
<br>
On Fri, Jan 17, 2014 at 2:56 PM, Herb Sutter &lt;<a href="mailto:hsutter@microsoft.com">hsutter@microsoft.com</a>&gt; wrote:<br>
&gt;&gt; Note that this post from Herb arrived after<br>
&gt;&gt; <a href="http://www.open-std.org/pipermail/ub/2014-January/000418.html">http://www.open-std.org/pipermail/ub/2014-January/000418.html</a> but was sent<br>
&gt;&gt; before, so the thread got a little mixed up.<br>
&gt;<br>
&gt; Yes, I've been trying to reply less on this thread until that sync'ed back<br>
&gt; up. :)<br>
&gt;<br>
&gt; From what I've learned in this thread, the (rough) intended C&#43;&#43; model for<br>
&gt; PODs (assuming memory of the right size/alignment) would seem to be &quot;the<br>
&gt; lifetime of a B starts when you write to the memory as a B, and ends when<br>
&gt; you free the memory or write to the memory as different type.&quot; [Disclaimer:<br>
&gt; I'm not sure if &quot;read from the memory as a B&quot; also starts lifetime.&quot;]<br>
&gt;<br>
&gt; I think we can do better, but it seems like that's the (rough) intent of the<br>
&gt; status quo, leaving aside the question of whether the wording actually says<br>
&gt; that.<br>
&gt;<br>
&gt; *If* that is the (rough) intent, then in:<br>
&gt;<br>
&gt;&gt; &nbsp; void *p = malloc(sizeof(B)); // 1<br>
&gt;&gt;<br>
&gt;&gt; &nbsp; B* pb = (B*)p; // 2<br>
&gt;&gt;<br>
&gt;&gt; &nbsp; pb-&gt;i = 0; // 3<br>
&gt;&gt;<br>
&gt;&gt; &nbsp; short* ps = (short*)p; // 4<br>
&gt;&gt; &nbsp; *ps = 0; // 5<br>
&gt;&gt;<br>
&gt;&gt; &nbsp; free(p); // 6<br>
&gt;<br>
&gt;<br>
&gt; I assume that the reasoning would be that:<br>
&gt;<br>
&gt; line 3 starts the lifetime of a B (we're writing to the bits of a B member,<br>
&gt; not just any int)<br>
&gt; line 5 ends the lifetime of that B and begins the lifetime of a short<br>
&gt; line 6 ends the lifetime of that short<br>
&gt;<br>
&gt;<br>
&gt; Again ignoring whether this is desirable, is that (roughly) the intent of<br>
&gt; the current wording?<br>
&gt;<br>
&gt;<br>
&gt; If yes, does the wording express it (a) accurately and (b) clearly?<br>
&gt;<br>
&gt;<br>
&gt; Finally, regardless of the above answer, do we want to change anything about<br>
&gt; the legality or semantics of the above type-punning code, such as possibly<br>
&gt; having a &quot;type-safe mode&quot; where such code is somehow not allowed unless in<br>
&gt; an &quot;extern &quot;C-compat&quot;&quot; block or something?<br>
&gt;<br>
&gt;<br>
&gt; Herb<br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt; ________________________________<br>
&gt; From: <a href="mailto:ub-bounces@open-std.org">ub-bounces@open-std.org</a> &lt;<a href="mailto:ub-bounces@open-std.org">ub-bounces@open-std.org</a>&gt; on behalf of Jeffrey<br>
&gt; Yasskin &lt;<a href="mailto:jyasskin@google.com">jyasskin@google.com</a>&gt;<br>
&gt; Sent: Friday, January 17, 2014 1:34 PM<br>
&gt;<br>
&gt; To: WG21 UB study group<br>
&gt; Subject: Re: [ub] type punning through congruent base class?<br>
&gt; &nbsp;<br>
&gt; Note that this post from Herb arrived after<br>
&gt; <a href="http://www.open-std.org/pipermail/ub/2014-January/000418.html">http://www.open-std.org/pipermail/ub/2014-January/000418.html</a> but was sent<br>
&gt; before, so the thread got a little mixed up.<br>
&gt;<br>
&gt; On Thu, Jan 16, 2014 at 11:38 AM, Herb Sutter &lt;<a href="mailto:hsutter@microsoft.com">hsutter@microsoft.com</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt; Richard, it cannot mean that (or if it does, IMO we have an obvious bug)<br>
&gt;&gt; for at least two specific reasons I can think of (below), besides the<br>
&gt;&gt; general reasons that it would not be sensical and would violate type safety.<br>
&gt;<br>
&gt;<br>
&gt; We do have an obvious bug in [basic.life]p1, &quot;The lifetime of an object of<br>
&gt; type T begins when storage with the proper alignment and size for type T is<br>
&gt; obtained&quot;, if we interpret &quot;obtained&quot; as &quot;obtained from the memory<br>
&gt; allocator&quot;. Even with strict uses of placement-new to change the type of<br>
&gt; memory, placement-new doesn't &quot;obtain&quot; any memory. If we interpret<br>
&gt; &quot;obtained&quot; as just &quot;the programmer intends a region of storage to be<br>
&gt; available for a T&quot;, as I think Richard is suggesting, the bug is only that<br>
&gt; we need the wording to be clearer.<br>
&gt;<br>
&gt;&gt; First, objects must have unique addresses. Consider, still assuming B is<br>
&gt;&gt; trivially constructible:<br>
&gt;&gt;<br>
&gt;&gt; &nbsp; void *p = malloc(sizeof(B));<br>
&gt;<br>
&gt;<br>
&gt; The lifetime of a B starts some time after-or-including the malloc() call in<br>
&gt; the above line and the access of 'pb-&gt;i' two lines down. [basic.life]p5<br>
&gt; (&quot;Before the lifetime of an object has started ... The program has undefined<br>
&gt; behavior if ... the pointer is used to access a non-static data member&quot;)<br>
&gt;<br>
&gt; The assignment to 'i' might start the lifetime of an 'int' subobject, but<br>
&gt; that's not enough to make the use of 'pb-&gt;i' defined if no 'B's lifetime has<br>
&gt; started.<br>
&gt; &nbsp;<br>
&gt;&gt;<br>
&gt;&gt; &nbsp; B* pb = (B*)p;<br>
&gt;&gt; &nbsp; pb-&gt;i = 0;<br>
&gt;<br>
&gt;<br>
&gt; The lifetime of the B *ends* when its storage is re-used for the 'short'<br>
&gt; ([basic.life]p1 &quot;The lifetime of an object of type T ends when ... the<br>
&gt; storage which the object occupies is reused&quot;), as Daveed said. This happens<br>
&gt; some time after the access in the previous line, and the assignment two<br>
&gt; lines down.<br>
&gt; &nbsp;<br>
&gt;&gt;<br>
&gt;&gt; &nbsp; short* ps = (short*)p;<br>
&gt;&gt; &nbsp; *ps = 0;<br>
&gt;&gt;<br>
&gt;&gt; This cannot possibly be construed as starting the lifetime of a B object<br>
&gt;&gt; and a short object, else they would have the same address, which is illegal.<br>
&gt;&gt; Am I missing something?<br>
&gt;<br>
&gt;<br>
&gt; Both a B object and a short object have their lifetimes started in your code<br>
&gt; snippet, but the lifetimes don't overlap.<br>
&gt;<br>
&gt; Confusingly, the start of these lifetimes is *not* called out in any<br>
&gt; particular line of code; it's implied by them. In particular, the casts<br>
&gt; don't have any lifetime effects (contra the straw man at<br>
&gt; <a href="http://www.open-std.org/pipermail/ub/2014-January/000406.html">http://www.open-std.org/pipermail/ub/2014-January/000406.html</a>). The code<br>
&gt; would be just as defined (or undefined) written as:<br>
&gt;<br>
&gt; &nbsp; void *p = malloc(sizeof(B));<br>
&gt;<br>
&gt; &nbsp; B* pb = (B*)p;<br>
&gt; &nbsp; short* ps = (short*)p;<br>
&gt; &nbsp; pb-&gt;i = 0;<br>
&gt;<br>
&gt; &nbsp; *ps = 0;<br>
&gt;<br>
&gt;<br>
&gt; As Matt alluded to in<br>
&gt; <a href="http://www.open-std.org/pipermail/ub/2014-January/000456.html">http://www.open-std.org/pipermail/ub/2014-January/000456.html</a>, it might be<br>
&gt; possible to say that all lifetime effects are called out in explicit<br>
&gt; expressions without breaking C compatibility, *if* we instead say that<br>
&gt; accessing the members of objects with trivial constructors can be done<br>
&gt; outside of the lifetime of such objects. I have no idea whether that would<br>
&gt; be better or worse than saying that lifetime effects can be implied.<br>
&gt;<br>
&gt;<br>
&gt; Jeffrey<br>
&gt;<br>
&gt;<br>
&gt; _______________________________________________<br>
&gt; ub mailing list<br>
&gt; <a href="mailto:ub@isocpp.open-std.org">ub@isocpp.open-std.org</a><br>
&gt; <a href="http://www.open-std.org/mailman/listinfo/ub">http://www.open-std.org/mailman/listinfo/ub</a><br>
&gt;<o:p></o:p></p>
</div>
</div>
</div>
</body>
</html>