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

Introducing C++ Swift Interop #25602

Merged
merged 1 commit into from
Mar 25, 2024

Conversation

nmahendru
Copy link

@nmahendru nmahendru commented Mar 7, 2024

e88f01a

Introducing C++ Swift Interop
https://bugs.webkit.org/show_bug.cgi?id=271263
rdar://123331949

Reviewed by Alex Christensen, Geoffrey Garen and Elliott Williams.

This is an examplar of the C++ Swift interop feature.
We have randomly chosen the Digest Implementation to be the first one to adopt this.
The Compiler feature is only available for newer platforms to code has been guarded
with ifdefs.

The changes in AbortWithReasonSPI.h are to allow the Swift Generator to work.
It, at the moment cannot handle headers included inside `extern C` blocks.

Input parameteres to Swift have been intentionally chosen as spans as
swift, at the moment my make copies of inputs for safety guarantees.
Copying a span is cheap so that is Okie.
On the return path, Swift calls the WTF::Vector move constructor(confirmed in debugger).

* Source/WTF/wtf/PlatformHave.h:
* Source/WTF/wtf/spi/darwin/AbortWithReasonSPI.h:
* Source/WebCore/Configurations/WebCore.xcconfig:
* Source/WebCore/PAL/Configurations/PAL.xcconfig:
* Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj:
* Source/WebCore/PAL/pal/PALSwift/CryptoKitShim.swift:
(AesGcm.test(_:)):
(AesKwRV.errCode):
(AesKwRV.outputSize):
(HashFunction.update(_:)):
(Digest.sha1(_:)):
(Digest.sha256(_:)):
(Digest.sha384(_:)):
(Digest.sha512(_:)):
(AesKwReturnValue.errCode): Deleted.
(AesKwReturnValue.outputSize): Deleted.
* Source/WebCore/PAL/pal/PALSwift/UnsafeOverlays.swift: Added.
(HashFunction.update(_:)):
* Source/WebCore/PAL/pal/PALSwiftModule.h: Copied from Source/WTF/wtf/spi/darwin/AbortWithReasonSPI.h.
* Source/WebCore/PAL/pal/crypto/commoncrypto/CryptoDigestCommonCrypto.cpp: Renamed from Source/WebCore/PAL/pal/crypto/commoncrypto/CryptoDigestCommonCrypto.mm.
(PAL::CryptoDigest::computeHash):
* Source/WebCore/PAL/pal/crypto/openssl/CryptoDigestOpenSSL.cpp:
(PAL::createCryptoDigest):
(PAL::CryptoDigest::computeHash):
* Source/WebCore/PAL/pal/module.modulemap: Added.
* Source/WebCore/SourcesCocoa.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/crypto/CryptoAlgorithm.cpp:
(WebCore::CryptoAlgorithm::dispatchDigest):
* Source/WebCore/crypto/cocoa/CryptoAlgorithmAESGCMMac.cpp: Renamed from Source/WebCore/crypto/cocoa/CryptoAlgorithmAESGCMMac.mm.
(WebCore::encryptCryptoKitAESGCM):
(WebCore::CryptoAlgorithmAESGCM::platformEncrypt):
* Source/WebCore/crypto/cocoa/CryptoAlgorithmAESKWMac.cpp: Renamed from Source/WebCore/crypto/cocoa/CryptoAlgorithmAESKWMac.mm.
(WebCore::wrapKeyAESKWCryptoKit):
(WebCore::unwrapKeyAESKWCryptoKit):
* Source/WebCore/crypto/cocoa/CryptoUtilitiesCocoa.cpp:

Canonical link: https://commits.webkit.org/276651@main

be30731

Misc iOS, tvOS & watchOS macOS Linux Windows
βœ… πŸ§ͺ style βœ… πŸ›  ios βœ… πŸ›  mac βœ… πŸ›  wpe βœ… πŸ›  wincairo
βœ… πŸ§ͺ bindings βœ… πŸ›  ios-sim βœ… πŸ›  mac-AS-debug ⏳ πŸ§ͺ wpe-wk2
βœ… πŸ§ͺ webkitperl βœ… πŸ§ͺ ios-wk2   πŸ§ͺ api-mac βœ… πŸ§ͺ api-wpe
βœ… πŸ§ͺ ios-wk2-wpt βœ… πŸ§ͺ mac-wk1 βœ… πŸ›  wpe-skia
βœ… πŸ›  πŸ§ͺ jsc βœ… πŸ§ͺ api-ios βœ… πŸ§ͺ mac-wk2 βœ… πŸ›  gtk
βœ… πŸ›  πŸ§ͺ jsc-arm64   πŸ›  tv βœ… πŸ§ͺ mac-AS-debug-wk2 ⏳ πŸ§ͺ gtk-wk2
βœ… πŸ›  tv-sim βœ… πŸ§ͺ api-gtk
  πŸ›  watch βœ… πŸ›  jsc-armv7
βœ… πŸ›  πŸ§ͺ unsafe-merge βœ… πŸ›  watch-sim   πŸ§ͺ jsc-armv7-tests

@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Mar 8, 2024
@nmahendru nmahendru force-pushed the eng/nitin-interop branch 2 times, most recently from f9f277e to 74a8fda Compare March 11, 2024 21:58
@nmahendru nmahendru changed the title Introducing C++ Swift Interop Dump the generated file in logs. Mar 13, 2024
Comment on lines 200 to 202
extension PALBytes: ContiguousBytes {
borrowing public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
try body(UnsafeRawBufferPointer(start:self.__dataUnsafe(), count: self.size()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any options to reduce our use of unsafety here? Or do we at least understand what safety might look like in the future?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underlying CryptoKitAPI eventually needs an UnsafeBufferPointer. Now matter how we wrap it we will have an unsafe somewhere, if not at this level then inside the wrapper around the API that expects UnsafeBufferPointer.

#include <cstdint>
#include <wtf/Vector.h>

using PALBytes = WTF::Vector<uint8_t>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's call this something like VectorUInt8. We want to be clear that all we've done is write out the template specialization for Vector<uint8_t>, and we want to avoid naming conflict with future specializations, which will be required because Swift only understands specializations and not templates.

let nonce = try AES.GCM.Nonce(
data: UnsafeBufferPointer(start: iv, count: Int(ivSize)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our goal is to write Swift code that is at least consistent with some future vision for safety, even if Swift is not yet safe. If Nonce() is expressed as an unsafe pointer API, I think we want an explicit wrapper or extension or replacement for it, so that our code is expressed in terms of safety. Maybe we need a separate file called "CryptoKitUnsafeAPIWrappers" or something like that, to hold all these abstractions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is only for Digest. I am going to cleanup the AESGCM, AESKW wrappers in a future PRs.

sealedBox.tag.copyBytes(
to: cipherText + Int(plainTextSize), count: sealedBox.tag.count)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No bounds check here, so we need a wrapper that expresses the bounds check.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using: SymmetricKey(
data: UnsafeBufferPointer(start: key, count: Int(keySize))))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need a wrapper that expresses a safe way to construct a key.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are other cases like this too, but I won't comment on each one. One way to get a close approximation is to search for "unsafe" in the code; though some unsafe pointers will instantiate implicitly.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nmahendru nmahendru force-pushed the eng/nitin-interop branch 2 times, most recently from 9214182 to e949499 Compare March 19, 2024 22:53
Copy link
Contributor

@emw-apple emw-apple left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r+ with formatting nits

@@ -53,7 +53,8 @@ FRAMEWORK_SEARCH_PATHS[sdk=macosx*] = $(WK_QUOTED_OVERRIDE_FRAMEWORKS_DIR);

SYSTEM_FRAMEWORK_SEARCH_PATHS = $(inherited) $(WK_PRIVATE_SDK_DIR)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks $(SDK_DIR)$(SYSTEM_LIBRARY_DIR)/Frameworks;

HEADER_SEARCH_PATHS = PAL ForwardingHeaders /usr/include/libxslt /usr/include/libxml2 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore $(BUILT_PRODUCTS_DIR)$(WK_LIBRARY_HEADERS_FOLDER_PATH) $(WEBKITADDITIONS_HEADER_SEARCH_PATHS) $(ANGLE_HEADER_SEARCH_PATHS) $(LIBWEBRTC_HEADER_SEARCH_PATHS) $(OBJROOT)/PAL.build/PAL.build/DerivedSources $(OBJROOT)/PAL.build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/PAL.build/DerivedSources $(HEADER_SEARCH_PATHS) $(SRCROOT);
HEADER_SEARCH_PATHS = PAL ForwardingHeaders /usr/include/libxslt /usr/include/libxml2 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore $(BUILT_PRODUCTS_DIR)$(WK_LIBRARY_HEADERS_FOLDER_PATH) $(WEBKITADDITIONS_HEADER_SEARCH_PATHS) $(ANGLE_HEADER_SEARCH_PATHS) $(LIBWEBRTC_HEADER_SEARCH_PATHS) $(OBJROOT)/PAL.build/PAL.build/DerivedSources $(OBJROOT)/PAL.build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/PAL.build/DerivedSources $(HEADER_SEARCH_PATHS) $(SRCROOT) $(SRCROOT)/PAL;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you remove the line above (L55)? I was asking about below (L57) :P

Basically, this file should have no changes to it.

@nmahendru nmahendru force-pushed the eng/nitin-interop branch 2 times, most recently from bac4d0a to 229a025 Compare March 22, 2024 01:21
@@ -28,7 +28,7 @@
#include <cstdint>
#include <wtf/Vector.h>

using VectorUInt8 = WTF::Vector<uint8_t>;
using VectorUInt8 = WTF::Vector<uint8_t, 0, CrashOnOverflow, 16, WTF::VectorBufferMalloc, WTF::IsCopyable::No>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just pass std::spans to Swift? Why do we need to pass vectors to these functions?

Copy link
Contributor

@cdumez cdumez Mar 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we'd pass a std::span<const uint8_t>, we wouldn't care if Swift copies it since it is cheap to copy

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the nonCopyable and using spans instead.

Copy link
Contributor

@geoffreygaren geoffreygaren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=me

#include <wtf/Vector.h>

using VectorUInt8 = WTF::Vector<uint8_t>;
using SpanUInt8 = std::span<const uint8_t>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's call this SpanConstUInt8, since const is a part of the type.

Comment on lines 196 to 201
extension HashFunction {
mutating func update(data: SpanUInt8) {
self.update(
bufferPointer: UnsafeRawBufferPointer(
start: data.__dataUnsafe(), count: data.size()))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To demonstrate our discipline of programming using safe constructs, and our expectation that future APIs will expose safe constructs, I think it's good for overlays that shim unsafe APIs like this to live in a separate file. Maybe "CryptoKitOverlay.swift", or we can put them all together in "UnsafeOverlays.swift".

If you'd like, you can make this change in the follow-up patch that removes the other unsafe pointers from this file.

hasher.update(data: data)
let digest = hasher.finalize()
var returnValue = VectorUInt8(T.Digest.byteCount)
returnValue.fill(0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to fill with zeroes here.

let digest = hasher.finalize()
var returnValue = VectorUInt8(T.Digest.byteCount)
returnValue.fill(0)
var counter = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually call this variable "index".

@achristensen07 achristensen07 added unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing and removed merging-blocked Applied to prevent a change from being merged labels Mar 25, 2024
https://bugs.webkit.org/show_bug.cgi?id=271263
rdar://123331949

Reviewed by Alex Christensen, Geoffrey Garen and Elliott Williams.

This is an examplar of the C++ Swift interop feature.
We have randomly chosen the Digest Implementation to be the first one to adopt this.
The Compiler feature is only available for newer platforms to code has been guarded
with ifdefs.

The changes in AbortWithReasonSPI.h are to allow the Swift Generator to work.
It, at the moment cannot handle headers included inside `extern C` blocks.

Input parameteres to Swift have been intentionally chosen as spans as
swift, at the moment my make copies of inputs for safety guarantees.
Copying a span is cheap so that is Okie.
On the return path, Swift calls the WTF::Vector move constructor(confirmed in debugger).

* Source/WTF/wtf/PlatformHave.h:
* Source/WTF/wtf/spi/darwin/AbortWithReasonSPI.h:
* Source/WebCore/Configurations/WebCore.xcconfig:
* Source/WebCore/PAL/Configurations/PAL.xcconfig:
* Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj:
* Source/WebCore/PAL/pal/PALSwift/CryptoKitShim.swift:
(AesGcm.test(_:)):
(AesKwRV.errCode):
(AesKwRV.outputSize):
(HashFunction.update(_:)):
(Digest.sha1(_:)):
(Digest.sha256(_:)):
(Digest.sha384(_:)):
(Digest.sha512(_:)):
(AesKwReturnValue.errCode): Deleted.
(AesKwReturnValue.outputSize): Deleted.
* Source/WebCore/PAL/pal/PALSwift/UnsafeOverlays.swift: Added.
(HashFunction.update(_:)):
* Source/WebCore/PAL/pal/PALSwiftModule.h: Copied from Source/WTF/wtf/spi/darwin/AbortWithReasonSPI.h.
* Source/WebCore/PAL/pal/crypto/commoncrypto/CryptoDigestCommonCrypto.cpp: Renamed from Source/WebCore/PAL/pal/crypto/commoncrypto/CryptoDigestCommonCrypto.mm.
(PAL::CryptoDigest::computeHash):
* Source/WebCore/PAL/pal/crypto/openssl/CryptoDigestOpenSSL.cpp:
(PAL::createCryptoDigest):
(PAL::CryptoDigest::computeHash):
* Source/WebCore/PAL/pal/module.modulemap: Added.
* Source/WebCore/SourcesCocoa.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/crypto/CryptoAlgorithm.cpp:
(WebCore::CryptoAlgorithm::dispatchDigest):
* Source/WebCore/crypto/cocoa/CryptoAlgorithmAESGCMMac.cpp: Renamed from Source/WebCore/crypto/cocoa/CryptoAlgorithmAESGCMMac.mm.
(WebCore::encryptCryptoKitAESGCM):
(WebCore::CryptoAlgorithmAESGCM::platformEncrypt):
* Source/WebCore/crypto/cocoa/CryptoAlgorithmAESKWMac.cpp: Renamed from Source/WebCore/crypto/cocoa/CryptoAlgorithmAESKWMac.mm.
(WebCore::wrapKeyAESKWCryptoKit):
(WebCore::unwrapKeyAESKWCryptoKit):
* Source/WebCore/crypto/cocoa/CryptoUtilitiesCocoa.cpp:

Canonical link: https://commits.webkit.org/276651@main
@webkit-commit-queue
Copy link
Collaborator

Committed 276651@main (e88f01a): https://commits.webkit.org/276651@main

Reviewed commits have been landed. Closing PR #25602 and removing active labels.

@webkit-commit-queue webkit-commit-queue removed the unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing label Mar 25, 2024
@webkit-commit-queue webkit-commit-queue merged commit e88f01a into WebKit:main Mar 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
8 participants