<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jun 27, 2016, at 7:15 PM, Dave Abrahams &lt;<a href="mailto:dabrahams@apple.com" class="">dabrahams@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="content-type" content="text/html; charset=utf-8" class=""><div dir="auto" class=""><div class=""><br class=""><br class=""><div class="">Sent from my moss-covered three-handled family gradunza</div></div><div class=""><br class="">On Jun 27, 2016, at 4:27 PM, Andrew Trick &lt;<a href="mailto:atrick@apple.com" class="">atrick@apple.com</a>&gt; wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Jun 27, 2016, at 3:35 PM, Dave Abrahams &lt;<a href="mailto:dabrahams@apple.com" class="">dabrahams@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">Casting from a raw pointer to a typed pointer is only more dangerous<br class="">than other raw pointer operations because it is the first step in this<br class="">sequence of operations, which is undefined:<br class=""><br class="">ptrA = rawPtr.cast(to: UnsafePointer&lt;A&gt;.self)<br class="">ptrA.initialize(with: A())<br class="">ptrA.deinitialize()<br class=""><br class="">ptrB = rawPtr.cast(to: UnsafePointer&lt;B&gt;.self)<br class="">ptrB.initialize(with: B())<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">But it's trivial to get undefined behavior without any of that. &nbsp;Just:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">&nbsp;_ = rawPtr.load(UnsafePointer&lt;NonTrivialType&gt;.self)</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></div></blockquote></div><br class=""><div class=""><div class="">That's another way to obtain a typed pointer, but by itself it is well defined.</div></div></div></blockquote><div class=""><br class=""></div>Sorry, I meant to dereference that typed pointer as part of the expression. Now boom.</div></div></blockquote><div><br class=""></div><div>Loading an UnsafePointer&lt;T&gt; from the contents of the raw pointer’s memory is fine if that’s what the memory contains. Dereferencing the loaded typed pointer is fine if that memory has been previously initialized with value of NonTrivialType.</div><div><br class=""></div><div>Also, loading NonTrivialType directly from a raw pointer is fine if the memory contains an initialized NonTrivialType. This is fine:</div><div><br class=""></div><div>&nbsp; let v = rawPtr.load(NonTrivialType.self)</div><div><br class=""></div>It returns an initialized `v` (a proper copy of the value in memory).</div><div><br class=""><blockquote type="cite" class=""><div class=""><div dir="auto" class=""><div class=""><blockquote type="cite" class=""><div class=""><div class=""><div class="">This is an important point, so I want to make sure I’m getting it across.</div><div class=""><br class=""></div><div class="">The following code is well-defined:</div><div class="">```</div><div class="">ptrA = rawPtr.initialize(with: A())</div><div class="">ptrA.deinitialize()</div><div class="">ptrB = rawPtr.initialize(with: B())</div><div class="">```</div><div class="">The following code is undefined:</div><div class="">```</div><div class="">ptrA = rawPtr.cast(to: UnsafePointer&lt;A&gt;.self)</div><div class="">ptrA.initialize(with: A())</div><div class="">ptrA.deinitialize()</div><div class="">ptrB = rawPtr.cast(to: UnsafePointer&lt;B&gt;.self)</div><div class="">ptrB.initialize(with: B())</div><div class="">```</div><div class="">It is hard to spot the difference between the two styles without drawing attention to the unsafe cast.</div></div></div></blockquote>How is that substantially different from my example?</div></div></div></blockquote><div><br class=""></div><div>There are different sources of memory unsafety. One rule is that (roughly) when memory is dereferenced as a type it should contain an initialized value of that type (or related type). As long as users follow this very intuitive rule, and don’t force-cast into a typed pointer, then the raw pointer API is very safe!</div><div><br class=""></div><div>Another source of memory unsafety is strict aliasing. This is not intuitive.</div><div><br class=""></div><div>I am showing an example in which the memory location is never accessed using a type that is inconsistent with its initialized value. There is nothing wrong with the order and type of the initialization, access, deinitialization operations, so the user has followed the first, intuitive rule. The only thing wrong with my example is that the initialization uses a typed pointer. You can’t have two initializations of the same memory both using a typed pointer but with unrelated types.</div><div><br class=""></div><div>All of this presumes that `A` and `B` are layout compatible (same alignment and size).</div><div><br class=""></div><div>It’s true that the user could run into the same problem if they obtain a typed pointer via unsafeBitCast or rawPtr.load(UnsafePointer&lt;T&gt;). But we don’t want to provide an API explicitly for converting raw pointers into typed pointers without indicating that it opens up a new safety hole…</div><div><br class=""></div><div>The *safe* way to get a typed pointer is this:</div><div>&nbsp; let ptrA = rawPtr.initialize(A.self, with: A())</div><div><br class=""></div><div>If you’re getting a typed pointer any other way then you need to be aware of the strict aliasing rules, which I suspect most users will not want to think about.</div><div><br class=""></div><div>So, UnsafeRawPointer.cast(to: UnsafePointer&lt;T&gt;.Type) is *not* as safe as any other operation because it opens up a very subtle issue involving strict aliasing.</div><div><br class=""></div><div>-Andy</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="auto" class=""><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div class=""><div class="">I considered naming the cast `UnsafeRawPointer.bind&lt;T&gt;(to: T.Type)` to indicate that the allocated memory is being bound to a type for the entire duration of its allocation. But it's actually the call to `initialize` a typed pointer that binds the type.</div></div><div class=""><br class=""></div><div class="">-Andy</div></div></blockquote></div></div></div></blockquote></div><br class=""></body></html>