了解如何混合使用 c、c++ 和 swift,同时提高 app 的安全性。我们将介绍如何在 swift 代码中找到不安全的 c 和 c++ api 调用位置、如何更安全地调用这些 api,以及如何使 app 中的现有 c 和 c++ 代码默认处于更安全的状态。
此文章由AI生成,可能存在错误,如有问题,请联系djs66256@163.com
安全混合使用 C、C++ 与 Swift:实现跨语言安全互操作
在现代应用开发中,混合使用 Swift 与 C/C++ 代码的情况十分常见。本文将详细介绍如何在保证安全性的前提下实现跨语言调用,帮助开发者避免常见的安全隐患。
引言
随着 Swift 在应用开发中的普及,许多开发者都会面临与现有 C/C++ 代码库互操作的需求。然而,这种混合编程方式可能带来严重的安全隐患,特别是当涉及到指针操作时。苹果安全语言扩展团队经理 Yeoul 在 WWDC 演讲中详细介绍了如何解决这些问题。
定位不安全调用
Swift 6.2 引入的”严格内存安全”编译模式可以帮助开发者识别潜在的 unsafe 调用。例如:
1 | var imageData = [UInt8](repeating: 0, count: imageDataSize) |
在启用该模式后,编译器会明确警告这种不安全构造,提示开发者需要标记为”unsafe”。
要在项目中启用严格内存安全模式,开发者需要在 Xcode 项目设置中进行手动配置。这种模式能够标记所有不安全代码并解释其原因,是发现混合编程安全问题的第一道防线。
安全调用 C/C++ 代码
指针安全问题
原始指针最大的安全挑战在于缺乏边界保护和生命周期管理。Swift 6.2 引入了新型安全指针 Span
和 MutableSpan
,既保留了指针的高效性,又内置了安全防护。
添加安全注解
开发者可以通过添加特定注解来提升指针安全性:
边界保护:使用
__counted_by
注解显式关联指针与元素数量1
void invertImage(uint8_t *__counted_by(imageSize) imagePtr __noescape, size_t imageSize);
生命周期管理:使用
__noescape
声明参数不逃逸函数范围1
void applyGrayscale(CxxSpanOfByte imageView __noescape);
返回值安全:使用
__lifetimebound
确保返回值的生命周期正确1
CxxSpanOfByte scanImageRow(CxxSpanOfByte imageView __lifetimebound, size_t width, size_t rowIndex);
安全导入自定义 C++ 类型
对于自定义的 C++ 类型,开发者可以通过特定的注解实现安全导入:
视图类型:使用
SWIFT_NONESCAPABLE
注解确保不超越所指内存的生命周期1
2
3
4
5struct ImageView {
std::span<uint8_t> pixelBytes;
int width;
int height;
} SWIFT_NONESCAPABLE;引用计数类型:使用
SWIFT_SHARED_REFERENCE
指定引用计数函数1
2
3
4
5
6struct ImageBuffer {
std::vector<uint8_t> data;
std::atomic<unsigned> refCount;
} SWIFT_SHARED_REFERENCE(retain_image_buffer, release_image_buffer);
ImageBuffer* createImage() SWIFT_RETURNS_RETAINED;
提升 C/C++ 代码安全性
虽然无法完全消除 C/C++ 的安全隐患,但开发者可以采取以下措施提升安全性:
- 启用 C++标准库强化功能,对
std::span
等标准容器进行边界检查 - 启用 C++不安全缓冲区错误检查,强制使用
std::span
代替原始指针 - 使用 C边界安全扩展,通过
__counted_by
等注解为指针添加边界信息
这些安全特性可以在 Xcode 的项目设置中统一启用。
总结与最佳实践
为确保混合语言编程的安全性,开发者应当遵循以下最佳实践:
- 在 Swift 项目中启用严格内存安全模式
- 为所有 C/C++ API 添加适当的安全注解
- 开启 C/C++ 的边界安全特性
苹果正在与开源社区合作完善语言间的安全互操作机制,开发者可以参考以下资源了解更多信息:
相关视频
文档资料
-fbounds-safety: Enforcing bounds safety for C
Safely Mixing Swift and C++