[swift-evolution] [Review] SE-0107: UnsafeRawPointer API (binding memory to type)

Dave Abrahams dabrahams at apple.com
Tue Jul 5 10:06:18 CDT 2016

on Mon Jul 04 2016, Jacob Bandes-Storch <swift-evolution at swift.org> wrote:

> This is the first version of this proposal which I've had time to read. I
> like it a lot overall. If I have some more time, I may try pulling the
> branch and writing some code with it to see how it feels. (If we could get
> a toolchain built from the branch, that might help others review it.)
> Here are a handful of minor comments:
> - Naming: "bindMemory(to:capacity:)", being "verb-ish", seems incongruous
> with "assumingMemoryBound(to:)" and "withMemoryRebound(to:capacity:_:)".
> How about "bindingMemory(to:capacity:)" ?

That was intentional. It has side-effects in the user model, so it is
actually appropriate that it forms an active verb phrase.

> - Would it be possible for "+(UnsafeRawPointer, Int) -> UnsafeRawPointer"
> to accept any Integer or FixedWidthInteger, rather than only Int?
> - Why allow/encourage multiple calls to bindMemory on the same RawPointer?

The reason to allow it are:

0. Typed access is faster and we don't want to relegate important use
   cases to untyped access.

1. We want to be able to use a single piece of memory for typed access
   to T and then reused for typed access to U as long as it is properly
   aligned and the T has been destroyed, without having to return it to
   the allocator.

2. We want to support the use of known layout compatibility to safely
   deal with type impedance mismatches (like CChar/Int8/UInt8 and
   (Double,Double)/Complex) at API boundaries.

I don't know where you see it encouraged.

> These APIs do a good job of making aliasing explicit by introducing data
> dependencies between pointers (you can only use a typed pointer after
> obtaining it from a raw pointer, and you can recover the raw pointer for
> later use by deinitializing the typed pointer). So, I would think the
> guidelines should prefer bindMemory to be used only once on a particular
> RawPointer value.

If you stick to the UnsafePointer APIs, that will be the effect.  The
use of UnsafeRawPointer is something you only need to get into in
specialized circumstances.

> And minor notes about the proposal itself:
> - strideof(Int.self) is used in most examples, but sizeof(Int.self) appears
> in one of them (the "normalLifetime()" example).
> - I think there must be a mistake in this example, because pA is already
> bound and bindMemory was only defined for untyped RawPointers:
>     func testInitAB() {
>       // Get a raw pointer to (A, B).
>       let p = initAB()
>       let pA = p.bindMemory(to: A.self, capacity: 1)
>       printA(pA)
>       printB((pA + 1).bindMemory(to: B.self, capacity: 1))   //<<< should
> this be (p+1) rather than (pA+1)?
>     }

Good eye, but it's not (p + 1).  You actually need to move p by the
least value >= MemoryLayout<A>.size that leaves the pointer properly
aligned for B.

> Jacob
> On Mon, Jul 4, 2016 at 3:32 PM, Andrew Trick via swift-evolution <
> swift-evolution at swift.org> wrote:
>> On Jun 28, 2016, at 11:05 PM, Chris Lattner <clattner at apple.com> wrote:
>> Hello Swift community,
>> The review of “SE-0107: UnsafeRawPointer API” begins now and runs through
>> July 4, 2016. The proposal is available here:
>> https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md
>> I've revised the proposal again based on extremely helpful feedback from
>> DaveA and Jordan.
>> This revision expands on the concept of formally binding the memory type
>> that I was recently working on with Dmitri. Now we can clearly define pre
>> and post conditions on memory operations and pointer casts that can be used
>> to prove the type safety. The model is now simpler, more complete, and easy
>> to reason about locally. This will help developers reason about correctness
>> and make it easy to implement a sanitizer that verifies the type safety of
>> UnsafePointer operations.
>> Adding safety to pointer "casts" made it possible for me to actually
>> simplify the allocation and initialization APIs. I think both camps,
>> convenience and safety, will be happy.
>> You can see what changed in this pull request:
>> https://github.com/apple/swift-evolution/pull/408
>> Brief summary:
>> - Memory is dynamically bound to a single type.
>> - All typed access to memory, whether via a typed pointer or regular
>>   language construct, must be consistent with the memory's bound type
>>   (the access type must be related to the bound type). Typed access
>>   includes initialization, assignment, or deinitialization via a typed
>>   pointer.
>> - Memory remains bound after being deinitialized.
>> - Memory is implicitly bound or rebound to a type by initializing it
>>   via a raw pointer.
>> - A separate API now exists for explicity binding or rebinding memory
>>   to a type. This allows binding to be decoupled from initialization
>>   for convenience and efficiency. It also supports safe
>>   interoperability between APIs that used different, but layout
>>   compatible types.
>> - Using an API that accesses memory as a different type can now be
>>   accomplished by rebinding the memory. This effectively changes the
>>   type of any initialized values in memory. The compiler is still
>>   permitted to assume strict aliasing for accesses on either side of
>>   the operation that rebinds memory.
>> Andy
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution


More information about the swift-evolution mailing list