View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

WWDC25に戻る

  • 概要
  • トランスクリプト
  • コード
  • C、C++、Swiftを安全に併用する方法

    C、C++、Swiftを併用する際にアプリの安全性を向上させる方法を学びましょう。安全でないCやC++のAPIが呼び出されているSwiftコード内の箇所を特定してより安全に呼び出す方法や、アプリの既存のCおよびC++コードをデフォルトでより安全にする方法を紹介します。

    関連する章

    • 0:00 - イントロダクション
    • 2:39 - Swiftにおける安全でない呼び出しの特定
    • 4:55 - C/C++を安全に呼び出す方法
    • 7:25 - ポインタを受け取る関数
    • 17:13 - ポインタを返す関数
    • 20:16 - カスタム型のインポート
    • 26:57 - C/C++の安全性の向上
    • 30:48 - まとめ

    リソース

    • -fbounds-safety: Enforcing bounds safety for C
    • Safely Mixing Swift and C++
      • HDビデオ
      • SDビデオ

    関連ビデオ

    WWDC25

    • Swiftによるメモリ使用量とパフォーマンスの向上
  • このビデオを検索

    こんにちは Yeoulです AppleのSecure Language Extensionチームのマネージャーです アプリを作成する際は セキュリティを優先することが重要です これは 潜在的な攻撃者からユーザーの 個人情報を保護することを意味します これらの脅威アクターは 多くの場合 安全でない言語である CやC++で書かれたコードの 脆弱性を悪用します 明るい面としては アプリですでにSwiftを使用している場合 言語はデフォルトで安全です これは素晴らしいニュースです

    しかし 新しいコードをすべて Swiftで書いている場合でも アプリには コードベースの古い部分に まだCやC++のコードが含まれている 可能性があります または 外部ライブラリに 依存する場合があります これらの言語が混在する場合 Swiftの安全性保証が 損なわれないようにすることが重要です 簡単にまとめると 生のポインタを 受け取ったり返したりするCやC++の 関数を安全に呼び出すのは 非常に難しいという問題があります これらの関数を誤って呼び出すと バッファオーバーフローや 解放後の使用といったセキュリティや 安定性のバグを引き起こす可能性があります

    このため CやC++からのポインタは Swiftではunsafe型としてインポートされます たとえば Cの整数ポインタは UnsafeMutablePointerとしてインポートされます Swiftは 型名にわざと unsafeを入れています それにより 関数を呼び出すときに 通常の安全性保証に頼れないことを 知ることができます ただし いくつかの関数をSwiftから 安全に呼び出せることはわかっています しかし これまで CとC++には その方法を伝える術がありませんでした これがこのセッションの内容です

    まず Swiftの安全でない呼び出しを 特定するのに役立つ新しい機能 Strict Memory Safetyについて説明します

    次に CとC++の関数に注釈を付けて 不足している情報を伝えることで Swiftがそれらを安全に 呼び出せるようにする方法を説明します 次に カスタムC++の型に注釈を付けて 安全にインポートする方法を説明します 最後に Cベースの言語をSwiftのように 安全にすることは不可能ですが CとC++のコードを少しでも安全にするための ツールをいくつか紹介します

    Swift 6.2には 安全でないCおよびC++関数の 呼び出しの検出に役立つ新機能があります これを 私が作ったアプリで実演します このアプリでは ペットのかわいい プロフィール写真をユーザーが共有できます このアプリは 愛犬のミドルネームのような 機密性が非常に高い 個人情報にアクセスできるので 安全に保つ必要があります アプリはSwiftで書かれています ただし カスタム画像フィルタを 適用するために CとC++コードも呼び出します アプリ内でCやC++への安全でない 呼び出しをすべて見つけ それらを安全にする必要があります 厄介なのは そのような呼び出しを 見つけるのが難しい場合があることです Swiftはデフォルトでは安全ですが 特にCやC++と相互運用する場合 安全でないコンストラクタを 使用できます たとえば 水面下では &imageDataは UnsafeMutablePointerを作成しますが これは 名前から 安全でないことがわかります しかし このコードを読んでいるときに それに気付くのはそれほど簡単ではありません 安全でない関数への すべての呼び出しを見つけるために Swift 6.2では Strict Memory Safetyと呼ばれる 新しいコンパイラモードを使用できます Strict Memory Safetyがオンの場合 コンパイラは 安全でないコードを 理由を説明するノードとともに警告します

    Strict Memory Safetyは デフォルトでは 有効になっていませんが 私のアプリはセキュリティに配慮するので 私は間違いなくオンにするつもりです Xcodeでチェックしましょう

    プロジェクトのビルド設定でを に切り替えてオプトインします

    再ビルドすると コンパイラは安全でないコンストラクタを 見つけるのに役立つ警告を発します

    新しい警告がいくつか出てきました この安全でないコードのほとんどは CとC++のポインタに関係しています

    Swiftからこれらのポインタを使う関数を 安全に呼び出す方法を説明します

    しかしその前に CとC++のポインタを 安全に使うのが難しい理由をお話しします

    ポインタは強力で便利なツールです コピーすることなく メモリを調べる能力を 与えてくれます しかし 安全に使用するのは非常に困難です 問題の根本は CとC++が プログラマがミスを犯さないようにする 手助けをしていないことです そのため たとえば メモリの一部が 解放された後に誤って使ってしまったり バッファの境界を越えてアクセスしてしまうのを止めるものは何もありません

    ここで朗報です Swift 6.2では Spanと呼ばれる新しい 安全なポインタ型が導入されています これはポインタの利点を提供しながら 自動的にこれらのミスを防ぎます Spanはポインタのように機能しますが 安全性が組み込まれています Swiftは 安全でないことを 実行できないようにしてくれます また メモリを変更する必要がある場合は MutableSpanもあります Spanの詳細については 「Improved memory usage and performance with Swift」をご覧ください SwiftがCとC++のポインタを 安全でないポインタとしてではなく Spanとしてインポートできたら 素晴らしいことです

    残念ながら コンパイラは それを安全に行うための 2つの重要な情報を欠いています ポインタの境界に関する C++からの情報がなければ Swiftは範囲外アクセスを 防ぐことができません また ポインタの有効期間に関する C++からの情報がなければ Swiftは ポインタが解放された後の 使用を防ぐことができません 重要な考え方として プログラマが その欠けている情報を提供する場合 Swiftは安全でないポインタを SwiftのSpanとして扱うことができます

    Swift 6.2では CとC++のコードに 注釈を追加することで 不足している情報を コンパイラに提供できます そのコードの動作が変わることはありません ただ その仮定を明示的にするだけです これにより Swiftはポインタを使用する CとC++コードに対して 安全な呼び出しを行えます ポインタを取ったり返したりする関数に 注釈を付ける方法を説明します そのためにアプリに戻りましょう

    最初の警告は 生のポインタを取得する invertImage関数の使用に関するものです

    このような ポインタを パラメータとして取得する関数を 安全に呼び出す方法を紹介します

    前述したように 生のポインタは 境界情報が欠落しているため 境界内でアクセスしているかどうかを 検証する方法がありません 注意深く使用しないと 範囲外の メモリエラーが発生する可能性があります これはその一例です InvertImage関数が Swiftから呼び出されます この関数は 画像への生ポインタである imageポインタを取得し サイズは別のパラメータを持ちます

    しかし imageポインタは 単なる生のポインタなので 誤って大きすぎるサイズを 渡してしまうことを止めるものは 何もありません もしそうすれば 関数はバッファの境界を 越えて読み書きすることになります これこそがSpanが解決する 問題の1つです invertImageがSpanを受け取るSwift関数 としてインポートされたと想像してください そうすれば 生のポインタとサイズを別々に 渡す代わりに 直接Spanを渡せます そうすることで 間違ったサイズを渡す などのミスから自動的に保護されます Spanは常に それらが指す メモリの正しい境界情報を 運ぶからです 次に 水面下で コンパイラが Spanのアンラップを行い 正しいポインタとサイズを抽出して C関数に渡します そうすれば ミスの余地はありません

    コンパイラはこれを実行できますが 生のポインタとサイズの間の 接続が欠けています invertImage関数は ポインタが imageSize要素のバッファを参照していると 仮定していますが それは暗黙の仮定にすぎません この関係を明示的に表現して 人間とコンパイラの双方が 理解できるようにする必要があります これはcounted_by注釈で 表現できます この注釈は ポインタが指す メモリ内の要素の数を コンパイラに知らせます 次に 有効期間情報が欠落しているので ポインタはnoescapeという 別の注釈も必要となります しかし 今のところは無視して大丈夫です これについては後で説明します この追加情報を提供すると Spanを直接渡すことで Swiftから 関数を安全に呼び出すことができます その後 コンパイラが自動的に 残りの処理を行います この方法では ミスは起こりえません invertImage関数に戻ります

    invertImage関数にcounted_by注釈と noescape注釈を追加します

    装飾に移動して 同じ注釈を追加します

    その後 Swiftの呼び出し箇所に戻ります

    次に 使用されたimageDataを直接渡して Swiftから関数を呼び出します

    これで 安全でないポインタが関与 しなくなったため 警告はなくなりました

    次の警告は applyGrayScale関数に関するものです この関数が安全でないC++の型を 使用していることを示しています

    その関数のC++の 定義を見てみましょう 名前からわかるように applyGrayScaleは 入力画像に グレースケール効果を適用する関数です この関数は画像のビューを取得しますが これはC++のSpan型であることがわかります ここまでは SwiftのSpanの話をしてきました しかし C++にもSpanの概念があります SwiftがC++のSpanを安全でないとみなすため 両者は同じ問題を 解決しようとしているにもかかわらず 警告が表示されます SwiftのSpanと同様に C++のSpanは 誰かが所有する 連続メモリにアクセスするために 使われる標準的な型です それらには そのメモリと そのサイズへのポインタが含まれています C++のSpanはサイズを知っているため SwiftのSpanと同様に 範囲外アクセスを安全にチェックできます ただし SwiftのSpanとは異なり C++のSpanには有効期間情報がないため 割り当てられたメモリへのアクセスを 防ぐことはできません そのため C++のSpanを使用すると 解放後の使用バグが発生することがあります

    これはその一例です ApplyGrayScale関数が Swiftによって 作成された配列を指すImageView というC++のSpanを取得するとします

    applyGrayscaleの内部で 他の C++コードが後でそれを使用できるように おそらくcachedViewのような グローバル変数に そのポインタを格納するかもしれません

    しかし ここに問題があります 関数が返された後 Swiftは 他で使用されていないと仮定して 配列を解放するかもしれません 今 C++のコードは もはや有効なメモリを指していない ポインタを保持しています これはぶら下がりポインタであり このポインタへのアクセスは典型的な 解放後の使用バグです

    一方 SwiftのSpanは安全です ポインタが指すメモリより 長く存続することはできません 関数がSwiftのSpanを取得する場合 関数内でのみ使用できます 後で使用するためにcachedViewに保存するなど 保持することは許可されません 関数が終了した後に ポインタが保持される場合 その動作はエスケープと呼ばれます コンパイラは Spanがそのスコープを エスケープしようとするたびに このようなエラーを報告します

    このように ぶら下がりポインタは SwiftのSpanでは不可能であり 設計上 解放後の使用バグは回避されます

    C++のSpanは同じような保証を 提供しません 安全に使うには ぶら下がりポインタを回避するために imageViewパラメータを保持しないように 関数を手動で監査する必要があります

    パラメータがC++関数を エスケープしないことを確認したら 関数定義でその情報を 思い出す必要があります こうすることで 人間とコンパイラの両方が 関数の動作を理解できるようになります noescape注釈を追加すると それを行うのに役立ちます noescape注釈は 生のポインタと参照にも適用できます

    Swift 6.2以降 noescape注釈を持つC++のSpanパラメータは SwiftのSpanとして扱うことができます これはSwiftのSpanを直接applyGrayscaleに 渡せるようになったことを意味します これは非常に便利で 安全でない定型コードが不要になります C++関数の呼び出しがこれほど安全で 簡単であるのは驚くべきことです

    applyGrayscaleの定義に移動して

    imageViewパラメータに noescapeを追加し

    装飾にもnoescapeを追加します

    次に Swiftのコアサイトに戻ります

    これで 保存されていない可変バッファ ポインタへの一時的なアクセスを削除し imageDataから取得したSwiftのSpanを 直接渡すことができます

    これで安全にapplyGrayscaleを 呼び出せるので 警告はなくなりました

    次の警告はscanImageRowの 使用に関するもので これはC++のSpanを受け取り 別のC++のSpanを返します

    では C++のSpanのようなポインタを 返す関数を安全に呼び出すには どうすればよいのでしょうか?

    C++のSpanを返すのは危険な場合があります 指されているメモリがまだ有効かどうか 追跡できないためです これはその一例です ScanImageRowはimageViewを C++のSpanとして取得し imageDataの選択された行を指す 別のC++のSpanを返します 関数が返されると データの割り当てが解除されます しかし 返されたC++のSpanは まだそのメモリを指しており それはぶら下がりポインタです アクセスすると 解放後の使用となります 戻り値をC++のSpanではなく SwiftのSpanのように扱えるのであれば このバグは起こりえないでしょう これは コンパイラが 返されたメモリがまだ有効であり 安全に使えるとわかっていない限り SwiftのSpanを 返すことさえさせてくれないからです では 返されたSpanを実際に 使用しても安全なのはいつでしょうか? imageViewパラメータと 同じメモリの一部を指しています つまり imageViewが存続する間だけ 存続します

    この関係はlifetimeboundと呼ばれます

    それはまさに 返されたC++のSpanを SwiftのSpanとしてインポートするために Swiftが必要とする 欠けている情報です それをlifetimebound注釈で 表現することができます これで コンパイラを 安全に使用できるようになります

    scanImageRowの 定義に移動して

    scanImageRow関数の imageViewパラメータに lifetimebound注釈を追加します

    装飾も同じようにします

    lifetimebound注釈を使用して 関数はSwiftのSpanを取得し 別のSwiftのSpanを返すことができます Swiftのコア側に移動します

    ここで 安全でない ポインタアクセスを削除し SwiftのSpanを直接渡すことができます

    この関数は 安全でないポインタではなく SwiftのSpanを返すようになりました 再ビルドすると 警告は消えます

    CとC++のコードを呼び出す際の 安全性の低さに対処したので 警告はすべて消えました ここまでは CとC++のポインタをSwiftの Spanのように扱う方法について説明しました しかし Swiftに直接インポートし 注釈で安全に使用することができる C++の他の慣用的な型が いくつかあります これらはカスタムビュー型 および参照カウント型です まず カスタムC++のビュー型を安全に インポートする方法を見ていきます ビュー型は 所有していない メモリへのポインタや 参照を含む 構造体です つまり SwiftのSpanもビュー型です

    それでは SwiftのSpanを本当に 安全にしているものを詳しく見てみましょう 水面下では Spanは 特別な種類のSwift型である エスケープ不可としてマークされています エスケープ不可の型は コピーを作成することなく 別の型のメモリへのビューを 提供する型を実装するために よく使用されます Spanの場合と同様に Swiftは すべてのエスケープ不可の型が 現在のコンテキストを エスケープしないようにします これにより 指し示すメモリよりも長く 存続しないことを保証するので 解放後の使用バグから保護されます C++のビュー型は Swiftでエスケープ不可 として安全にインポートできます 必要なのは 注釈を追加することだけです

    これはその一例です 私のアプリには カスタムC++構造体 ImageViewがあり 画像の幅と高さ 画像のピクセルデータへの ポインタを格納しています imageViewはそのピクセルデータを所有していません それは別のオブジェクトに属しており そのオブジェクトは不要になったときに メモリを解放する役割を担っています

    つまり imageViewがエスケープするのは 安全ではありません もしエスケープすると ビューは そのメモリが解放された後にそのメモリを 使用する可能性があります

    そのため 型が決して エスケープしないようにする必要があります そのために SWIFT_NONESCAPABLE 注釈を追加できます このようにして コンパイラはC++の型を エスケープ不可としてインポートします 経験則として 構造体に 所有していないメモリへの ビューやポインタが含まれる場合は この注釈を使用する必要があります

    ビュー型だけでなく C++や他の多くの言語でも 型が参照先のメモリを所有し 参照カウントによって その参照を追跡することは 非常に一般的なイディオムです Swiftには 注釈を使用してこれらの型を 安全にインポートする機能があります たとえば C++の画像バッファ構造体は 基になるimageDataを所有しています 構造体の割り当てが解除されると imageDataも割り当て解除されます 画像バッファがSwiftの参照カウント型 としてインポートされるようにしたいので コンパイラは自動的に その有効期間を管理できます そのために SWIFT_SHARED_ REFERENCE注釈を使って Swiftが参照カウントをインクリメントし デクリメントするのに呼び出すべき関数を コンパイラに伝えます これでSwiftは 画像バッファを 参照カウント型と見なします

    しかし 画像バッファを安全に返すために コンパイラが必要とする 情報がもっとあります

    C++関数が 画像バッファを返すとき 2つの状況が考えられます 第一に 関数が新しく作成された 画像を返す場合 それが終了したときに 画像を解放するのは 呼び出し元の責任です この場合は メソッドにSWIFT_ RETURNS_RETAINED注釈を付けます これは 画像が使用されなくなったときに 呼び出し元で画像を解放するように Swiftコンパイラに指示します 第二に 関数がすでに存在する 画像への参照を返す場合 画像を保持したいのであれば 画像を保持するのは 呼び出し側の責任です この場合は メソッドにSWIFT_ RETURNS_UNRETAINED注釈を付けます これにより 画像を保持したい場合に Swiftコンパイラに対して 画像を保持する必要があることを伝えます これらの注釈を追加すると 所有権の期待が明示されるので Swiftはメモリを安全に管理できます

    欠落している情報を提供するために コードに注釈を付けることで SwiftはCとC++の関数と型を 安全に使用できます これらの注釈によって コードの動作が変更されることはありません コード内の仮定を 明示的にするだけです

    これまで取り上げた注釈と その使い方をまとめましょう

    関数パラメータや戻り値が ポインタやarray型であり それが1つ以上の要素の メモリを指している場合は counted_by注釈を使用して 要素の数を示します 他が所有するメモリを パラメータが参照し そのパラメータが関数をエスケープしない 場合は noescapeを使用します

    関数の返り値がメモリを参照し そのメモリの有効期間が パラメータの有効期間に依存する場合は lifetimebound注釈を追加します この情報を追加することで 使用するために 呼び出し箇所で式を必要としない 安全なSwiftのSpan型として Swiftがポインタを インポートできるようにします

    また SwiftがカスタムC++の型を安全に 管理するための注釈を追加することもできます C++の型がビュー ポインタ または 所有していないメモリへの参照を 格納する場合はSWIFT_ NONESCAPABLEを使用してください これにより コンパイラは型を エスケープ不可の型としてインポートします

    代わりに型が参照カウントされている場合は SWIFT_SHARED_REFERENCEを使用します その後 コンパイラはメモリを 自動的に管理します

    たくさんありましたね ビデオを一時停止して 休憩するなら 今がそのタイミングです 必ず戻って来てくださいね 次は CとC++のコードを より安全に扱うための とてもエキサイティングな 新しいツールを紹介します

    それでは CとC++のコードを どのように安全にできるかについて お話しします アプリでは SwiftがCとC++を安全に 呼び出せるように注釈を追加しました ただし 純粋なCとC++のコードは まだ安全ではありません 一歩間違えば簡単に セキュリティバグが発生します 理想を言えば そのコードをSwiftで 書き直して 完全な安全性を確保したいです しかし それは 現実的ではないこともあります CとC++をSwiftのように 安全にすることは不可能ですが CとC++で部分的な安全を提供する ツールをいくつか紹介します まず C++の境界の安全性を強化するために 開発したツールについて説明します

    なぜC++はまだ境界の安全性がないのか 疑問に思われるかもしれません 先ほど話したように Spanはすでに 境界情報を格納しています ただし このような Spanの配列の添え字に対して C++ではデフォルトで 境界が検査されないことが問題です また ベクターなどの他の 標準コンテナについても同じことが言えます Xcodeには C++ Standard Library Hardeningと呼ばれる機能があります これは 標準的なC++のビューと コンテナの配列の添え字に 境界検査があることを確認します また 標準ライブラリに他の いくつかの安全性チェックも追加されます

    C++ Standard Library Hardeningを 有効にした後でも まだ別の問題があります

    境界情報を持たないため 境界検査ができない 生のポインタを 使用することはできます したがって C++を使用する最善の方法は 生のポインタを避け C++のSpanのような標準型を使うことです

    これを支援するために Xcodeでは C++で安全でないポインタを 使用したときのエラーをオンにできます これにより コードを確認し 必要に応じて 生のポインタをC++のSpanや 標準コンテナに置き換えることができます

    注意点として これらのエラーは 境界の安全性に関するもので 有効期間に関するものではありません

    C++プロジェクトの境界を安全に保つには プロジェクトのビルド設定でを に設定します これにより C++Standard Library Hardeningが有効になり 安全でないバッファの使用エラーも すべて解消されます

    Cはどうでしょうか? C++とは異なり Cにはポインタに境界情報を持たせるための Spanのような標準型がありません そこで C向けに 境界の安全性を保証する 新しい言語拡張機能を開発しました これはXcodeで使えるようになりました この言語拡張機能を有効にすると コンパイラは Cコード全体で 境界情報が欠落している箇所を 教えてくれます 次に 境界の注釈を追加して 不足している情報を表現できます この例では バッファに counted_by注釈を追加できます この注釈は 以前に安全なSwiftとCの 相互運用のために使用されたものと同じです

    そうすると コンパイラは境界外の メモリアクセスを安全に把握する 境界検査を実行時に挿入します

    Xcodeのプロジェクト設定で すべてのCファイルに対して 境界の安全性の拡張機能を有効にできます 詳しくは llvm.org Webサイトの 境界の安全性に関するドキュメントを ご覧ください

    このセッションでは Swiftの安全性を確保し CやC++のコードを 安全に呼び出す方法について説明しました CとC++をSwiftのように 安全にすることは不可能ですが より安全にすることはできます

    ここでは C C++ Swiftを 混在させるときに 最高の安全性を得るためのヒントを いくつか紹介します

    SwiftでStrict Memory Safetyを オンにします これは 安全でないコンストラクタを 使用するたびに警告し CとC++のAPIの安全でない使用を 見つけるのに役立ちます 注釈を追加することで Swiftが安全でないCとC++のAPIを 安全に操作できることを確認します

    CとC++をデフォルトでより安全にします これを行うには CとC++の 新しい境界の安全性機能を有効にします

    私たちは オープンソースコミュニティと協力して C C++ Swiftをシームレスかつ安全に 連携させることを目指しています 皆さんのご参加とフィードバックは 私たちにとって非常に重要です

    ぜひお試しいただき 意見をお聞かせください ご視聴ありがとうございました

    • 3:19 - Unsafety can be subtle

      // Swift
      var imageData = [UInt8](repeating: 0, count: imageDataSize)
      filterImage(&imageData, imageData.count)
    • 4:01 - Strict memory safety

      // Swift
      var imageData = [UInt8](repeating: 0, count: imageDataSize)
      filterImage(&imageData, imageData.count)
      //warning: Expression uses unsafe constructs but is not marked with 'unsafe'
    • 8:00 - Raw pointers don't prevent out-of-bounds errors

      // C/C++
      void invertImage(uint8_t *imagePtr, size_t imageSize);
    • 8:21 - Raw pointers don't prevent out-of-bounds errors

      // Swift
      var imageData = [UInt8](repeating: 0, count: imageSize)
      invertImage(&imageData, imageSize)
    • 8:30 - Raw pointers don't prevent out-of-bounds errors

      // Swift
      var imageData = [UInt8](repeating: 0, count: imageSize)
      invertImage(&imageData, 1000000000000)
    • 8:48 - Solution for out-of-bounds error

      // Swift
      func invertImage(_ imagePtr : inout MutableSpan<UInt8>)
    • 8:54 - Solution for out-of-bounds error

      // Swift
      var imageDataSpan = imageData.mutableSpan
      invertImage(&imageDataSpan)
    • 9:58 - Express bounds information using __counted_by

      // C/C++
      void invertImage(uint8_t *__counted_by(imageSize) imagePtr __noescape, size_t imageSize);
    • 12:10 - Unsafe function declaration taking a C++ span

      // C++
      using CxxSpanOfByte = std::span<uint8_t>;
      void applyGrayscale(CxxSpanOfByte imageView);
    • 13:21 - Unsafe C++ function caching a C++ span

      // C++
      CxxSpanOfByte cachedView;
      void applyGrayscale(CxxSpanOfByte imageView) {
        cachedView = imageView;
        // Apply effect on image ...
      }
    • 14:08 - Swift Span prevents escaping scope

      // Swift
      var cachedView: MutableSpan<UInt8>?
      func applyGrayscale(_ imageView: inout MutableSpan<UInt8>) {
        cachedView = imageView // error: lifetime dependent value escapes its scope
        // Apply effect on image ...
      }
    • 15:18 - Express lifetime information using __noescape

      // C++
      CxxSpanOfByte cachedView;
      void applyGrayscale(CxxSpanOfByte imageView __noescape) {
        // Apply effect on image ...
      }
    • 15:56 - Safely use a C++ Span as a Swift Span

      // Swift
      var imageDataSpan = &imageData.mutableSpan
      applyGrayscale(&imageDataSpan)
    • 17:21 - Returned C++ Span is unsafe

      // C++
      CxxSpanOfByte scanImageRow(CxxSpanOfByte imageView,
                                 size_t width, size_t rowIndex);
    • 18:06 - Swift Spans prevent use-after-free by design

      // Swift
      func scanImageRow(_ imageView : inout MutableSpan<UInt8>,
                        _ width : Int, _ rowIndex : Int) -> MutableSpan<UInt8>
      // error: a function with a ~Escapable result requires '@lifetime(...)'
    • 18:47 - Express lifetime dependency with __lifetimebound

      // C++
      CxxSpanOfByte scanImageRow(CxxSpanOfByte imageView __lifetimebound,
                                 size_t width, size_t rowIndex);
    • 18:50 - Safely return a C++ Span as a Swift Span

      // Swift
      var imageDataSpan = imageData.mutableSpan
      var rowView = scanImageRow(&imageDataSpan, width, y)
    • 22:29 - Import a C++ view type as SWIFT_NONESCAPABLE

      // C++
      struct ImageView {
        std::span<uint8_t> pixelBytes;
        int width;
        int height;
      } SWIFT_NONESCAPABLE;
    • 23:31 - Import a C++ reference-counted type

      // C++
      struct ImageBuffer {
        std::vector<uint8_t> data;
        int width;
        int height;
        std::atomic<unsigned> refCount;
      } SWIFT_SHARED_REFERENCE(retain_image_buffer, release_image_buffer);
      
      void retain_image_buffer(ImageBuffer *_Nonnull buf);
      void release_image_buffer(ImageBuffer *_Nonnull buf);
    • 23:57 - Safely return a reference-counted type

      // C++
      ImageBuffer *_Nonnull createImage() SWIFT_RETURNS_RETAINED;
      ImageBuffer *_Nonnull getCachedImage() SWIFT_RETURNS_UNRETAINED;
    • 27:51 - C++ standard library hardening

      // C++
      void fill_array_with_indices(std::span<uint8_t> buffer) {
        for (size_t i = 0; i < buffer.size(); ++i) {
          buffer[i] = i;
        }
      }
    • 28:59 - C++ unsafe buffer usage errors

      // C++
      void fill_array_with_indices(uint8_t *buffer, size_t count) {
        for (size_t i = 0; i < count; ++i) {
          buffer[i] = i; // error: unsafe buffer access
        }
      }
    • 30:11 - Bounds safety extension for C

      // C
      void fill_array_with_indices(uint8_t *__counted_by(count) buf, size_t count) {
        for (size_t i = 0; i < count; ++i) {
          buf[i] = i;
        }
      }

Developer Footer

  • ビデオ
  • WWDC25
  • C、C++、Swiftを安全に併用する方法
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習とAI
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン