Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-9578] Data.withUnsafeBytes(_:) passes pointer pointing copied memory to closure on macOS #3566

Closed
norio-nomura opened this issue Dec 26, 2018 · 6 comments

Comments

@norio-nomura
Copy link
Contributor

Previous ID SR-9578
Radar None
Original Reporter @norio-nomura
Type Bug
Status Resolved
Resolution Invalid
Environment

swift-5.0-DEVELOPMENT-SNAPSHOT-2018-12-25-a on macOS

Additional Detail from JIRA
Votes 0
Component/s Foundation
Labels Bug
Assignee None
Priority Medium

md5: d854dde68a3c2dbf907f3d8b194f3568

Issue Description:

The pointerValue held by Data and the pointerValue of UnsafePointer passed to Data.withUnsafeBytes(_:) are different on macOS.

$ xcrun --toolchain org.swift.5020181225a swift
swift_oss_helper command enabled.
Welcome to Apple Swift version 5.0-dev (LLVM c351ac7354, Clang aadec4ff83, Swift 5cfc2e7ba9).
Type :help for assistance.
  1> import Foundation 
  2. let data = "test".data(using: .utf8)! 
  3. dump(data) 
  4. data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in 
  5.     dump(bytes) 
  6. }
▿ 4 bytes
  - count: 4pointer: 0x00007ffeefbff818
    - pointerValue: 140732920756248bytes: 4 elements
    - 116
    - 101
    - 115
    - 1160x00007ffeefbffb30
  - pointerValue: 140732920757040
$R0: UnsafePointer<UInt8> = 0x00007ffeefbffb30
data: Data = 4 bytes
  7> ^D

It seems that unnecessary memory copy is occurring.
This issue does not happen on Linux.

@belkadan
Copy link

belkadan commented Jan 7, 2019

Interestingly, while I don't see the same pointer in both places, I do see successive uses of withUnsafeBytes producing the same pointer:

import Foundation 
let data = "test".data(using: .utf8)! 
dump(data) 
data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in 
    dump(bytes) 
}
data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in 
    dump(bytes) 
}

I'm not quite sure what to make of that. Maybe withUnsafeBytes is doing a uniqueness check?

cc @phausler

@phausler
Copy link
Member

phausler commented Jan 7, 2019

“test” is small enough to be represented on the stack: so each call takes stack memory locations to pass into the closure (since the bytes are not valid past the call of the block)

@norio-nomura
Copy link
Contributor Author

This issue breaks code that depends on behavior "Immutable Data passes pointer pointing original memory to closure in withUnsafeBytes(_:)".
jpsim/Yams@bc13691

@phausler
Copy link
Member

phausler commented Jan 8, 2019

That is correct, it was technically the case before but was not commonly enforced (there were some subclasses of NSData that when bridged could do something similar). Now we have a more common case that has that behavior. This is almost the same change that happened to String when it gains the "smol" implementation.

It is worth noting that the cut-off for the byte pointer in the "smol" Data varies per architecture. If the payload can fit into the size of two pointers minus the storage for the length and the storage for the discriminator of the storage we opt for a non-heap implementation of Data.

@belkadan
Copy link

belkadan commented Jan 8, 2019

Closing this, then, since it's intended behavior and not indicative of a performance problem.

@norio-nomura
Copy link
Contributor Author

I confirmed that this issue occurs only when Data is small.
Thanks!

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@shahmishal shahmishal transferred this issue from apple/swift May 5, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants