<div dir="ltr">I don’t see any source for this claim in the <a href="https://developer.apple.com/documentation/swift/unsafemutablepointer/2295090-deallocate">documentation</a>, or the <a href="https://github.com/apple/swift/blob/master/stdlib/public/core/UnsafePointer.swift.gyb#L432">source code</a>. As far as I can tell the expected behavior is that partial deallocation “should” work.<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Sep 7, 2017 at 8:59 AM, Joe Groff <span dir="ltr"><<a href="mailto:jgroff@apple.com" target="_blank">jgroff@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5"><br>
> On Sep 6, 2017, at 4:46 PM, Taylor Swift <<a href="mailto:kelvin13ma@gmail.com">kelvin13ma@gmail.com</a>> wrote:<br>
><br>
><br>
><br>
>> On Sep 6, 2017, at 5:12 PM, Joe Groff <<a href="mailto:jgroff@apple.com">jgroff@apple.com</a>> wrote:<br>
>><br>
>><br>
>>> On Sep 6, 2017, at 3:07 PM, Taylor Swift <<a href="mailto:kelvin13ma@gmail.com">kelvin13ma@gmail.com</a>> wrote:<br>
>>><br>
>>><br>
>>><br>
>>>> On Sep 6, 2017, at 4:31 PM, Joe Groff <<a href="mailto:jgroff@apple.com">jgroff@apple.com</a>> wrote:<br>
>>>><br>
>>>><br>
>>>>> On Sep 6, 2017, at 2:28 PM, Andrew Trick <<a href="mailto:atrick@apple.com">atrick@apple.com</a>> wrote:<br>
>>>>><br>
>>>>><br>
>>>>>>> On Sep 6, 2017, at 1:12 PM, Joe Groff via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br>
>>>>>>><br>
>>>>>>><br>
>>>>>>> On Sep 6, 2017, at 1:06 PM, Taylor Swift <<a href="mailto:kelvin13ma@gmail.com">kelvin13ma@gmail.com</a>> wrote:<br>
>>>>>>><br>
>>>>>>><br>
>>>>>>><br>
>>>>>>>> On Wed, Sep 6, 2017 at 12:41 PM, Joe Groff via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br>
>>>>>>>> Currently, memory is deallocated by an instance method on UnsafeMutablePointer, deallocate(count:). Like much of the Swift pointer API, performing this operation on a buffer pointer requires extracting baseAddress! and count. It is very common for the allocation code above to be immediately followed by:<br>
>>>>>>>><br>
>>>>>>>> defer<br>
>>>>>>>><br>
>>>>>>>> {<br>
>>>>>>>> buffer.<br>
>>>>>>>> baseAddress?.deallocate(<wbr>capacity: buffer.count<br>
>>>>>>>> )<br>
>>>>>>>> }<br>
>>>>>>>><br>
>>>>>>>> This method is extremely problematic because nearly all users, on first seeing the signature of deallocate(capacity:), will naturally conclude from the capacity label that deallocate(capacity:) is equivalent to some kind of realloc()that can only shrink the buffer. However this is not the actual behavior — deallocate(capacity:) actually ignores the capacity argument and just calls free() on self. The current API is not only awkward and suboptimal, it is misleading. You can write perfectly legal Swift code that shouldn’t segfault, but still can, for example<br>
>>>>>>>><br>
>>>>>>>> var ptr = UnsafeMutablePointer<UInt8>.<wbr>allocate(capacity: 1000000<br>
>>>>>>>> )<br>
>>>>>>>> ptr.<br>
>>>>>>>> initialize(to: 13, count: 1000000<br>
>>>>>>>> )<br>
>>>>>>>> ptr.<br>
>>>>>>>> deallocate(capacity: 500000) // deallocate the second half of the memory block<br>
>>>>>>>> ptr[0] // segmentation fault<br>
>>>>>>>> where the first 500000 addresses should still be valid if the documentation is to be read literally.<br>
>>>>>>><br>
>>>>>>> The fact that the Swift runtime currently uses malloc/free is an implementation detail. Tracking deallocation size is a very useful optimization for better allocator backends, and C++ underwent an ABI break to make it so that sized delete can be supported. Maybe we can change the name to `deallocate(allocatedCapacity:<wbr>)` to make it clear that it isn't resizing the memory, and/or make the capacity argument optional so that you can pay for the overhead of the allocator deriving the size if it's inconvenient for the calling code to carry the size around, but we shouldn't remove the functionality altogether.<br>
>>>>>>><br>
>>>>>>> -Joe<br>
>>>>>>> ______________________________<wbr>_________________<br>
>>>>>>> swift-evolution mailing list<br>
>>>>>>> <a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
>>>>>>> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br>
>>>>>>><br>
>>>>>>> The idea is to get the house in order by removing all parameters from deallocate(), since that’s what it really does right now. Then, in the future, if Swift gets a more sophisticated allocator backend, a new method like deallocate(capacity:) or reallocate(toCapacity:) could be added without conflicting with the currently named deallocate(capacity:). However, using the function signature to pretend that it does something it can’t actually do right now is extremely dangerous.<br>
>>>>>><br>
>>>>>> I don't think that's a good idea in this case, because it's not unlikely we would explore an optimized allocator soon after ABI stability, and retrofitting these interfaces in a future version of Swift would put a deployment target limit on when they can be used, and mean that a lot of user code would need to be retrofitted to carry allocated capacities where needed to see any benefit.<br>
>>>>>><br>
>>>>>> -Joe<br>
>>>>><br>
>>>>> The fact that we’re using malloc and free is already part of the ABI because old libraries need to be able to deallocate memory allocated by newer libraries.<br>
>>>><br>
>>>> The compiler doesn't ever generate calls directly to malloc and free, and the runtime entry points we do use already take size and alignment on both allocation and deallocation.<br>
>>>><br>
>>>>> Within the standard library we could make use of some new deallocation fast path in the future without worrying about backward deployment.<br>
>>>>><br>
>>>>> Outside of the standard library, clients will get the benefits of whatever allocator is available on their deployed platform because we now encourage them to use UnsafeBufferPointer.<wbr>deallocate(). We can change the implementation inside UnsafeBufferPointer all we want, as long as it’s still malloc-compatible.<br>
>>>>><br>
>>>>> I’m sure we’ll want to provide a better allocation/deallocation API in the future for systems programmers based on move-only types. That will already be deployment-limited.<br>
>>>>><br>
>>>>> Absolute worst case, we introduce a sized UnsafePointer.deallocate in the future. Any new code outside the stdlib that wants the performance advantage would either need to<br>
>>>>> - trivially wrap deallocation using UnsafeBufferPointer<br>
>>>>> - create a trivial UnsafePointer.deallocate thunk under an availability flag<br>
>>>><br>
>>>> Since we already have sized deallocate, why would we take it away? If the name is misleading, we can change the name.<br>
>>>><br>
>>>> -Joe<br>
>>><br>
>>> Exactly, we are changing the name to `deallocate()`. As for the old `deallocate(capacity:)` method that *needs* to be removed because it is actively harmful. As I’ve explained it’s not enough to just drop in a sized backend later as an “implementation detail” because it’s not an implementation detail, you’re changing the fundamental behavior of that method.<br>
>><br>
>> It would remove a mode of "holding it wrong", but the specified behavior will not change; it has and will always fully deallocate the object being referenced in the cases where the call has defined behavior.<br>
><br>
> idk what you mean by it holding it wrong, but while the specified behavior won’t change the actual behavior *will* change, because right now the two don’t agree. We can’t just treat it as a bug to fix because it’s been around since the beginning of Swift and some people treat it as part of expected behavior, using the function like `free()`. This isn’t using it incorrectly, in fact in terms of behavior, passing a meaningful capacity argument to `deallocate(capacity:)` is *incorrect usage*, as demonstrated in the segfaulting example in the proposal.<br>
<br>
</div></div>The segfaulting example is an incorrect usage. The only valid parameters to deallocate(capacity:) are the base address of an allocation, and the original capacity passed into allocate(); it has never been intended to support partial deallocation of allocated blocks. It seems to me like this proposal is based on a misunderstanding of how the API works. The documentation and/or name should be clarified.<br>
<span class="HOEnZb"><font color="#888888"><br>
-Joe<br>
</font></span><div class="HOEnZb"><div class="h5"><br>
> “fixing” this bug will cause programs that once operated on previously valid assumptions of “free()” semantics to behave differently, without any warnings ever being generated. Conversely incorrect code will suddenly become “correct” though this is less of a problem.<br>
><br>
>> A sized implementation may fail more obviously when you violate the contract in the future. Not having sized deallocation is a known deficiency of the C model we've been fairly diligent about avoiding in Swift's allocation interfaces, and it would be extremely unfortunate for us to backpedal from it.<br>
>><br>
>> -Joe<br>
><br>
> Which is worse, an active gaping hole in Swift’s memory system, or potentially discouraging users from using a hypothetical future allocation API?<br>
><br>
> Making sure the existing allocation API is working properly is a prerequisite to introducing a future more advanced allocation API.<br>
<br>
</div></div></blockquote></div><br></div>