[P1] ARM64 iOS 上 RustBuffer 结构体跨 FFI 传参 ABI 不兼容,需全部改为 out-pointer 方式 #36

Closed
opened 2026-06-03 22:56:45 +08:00 by wangdl · 2 comments
Owner

背景

在 ARM64 iOS (iPhone 17 Pro Max 模拟器) 上,Swift 与 Rust 之间通过 C ABI 传递 RustBuffer(24 字节结构体,u64+u64+*mut u8)时,超过 16 字节的结构体应通过间接指针传递,但 Swift 和 C/Rust 编译器在内存布局上存在不一致,导致跨 FFI 传参时字段损坏。

已验证的修复方案:将结构体参数拆分为独立的 len/data/capacity 等原始类型参数,通过 out-pointer 传递。

已修复的函数

  • parseMarkdown -- 使用 ffi_zx_document_ffi_parse_markdown_separate(len, data, out_capacity, out_len, out_data, out_error_code)
  • ffi_zx_document_ffi_rustbuffer_from_bytes -- 使用 ffi_zx_document_ffi_rustbuffer_from_bytes_separate(len, data, out_capacity, out_len, out_data)
  • ffi_zx_document_ffi_rustbuffer_free -- 使用 ffi_zx_document_ffi_rustbuffer_free_separate(capacity, len, data)

待修复的函数(仍用旧的 struct-passing)

以下 Rust FFI 函数仍然通过结构体传参 RustBuffer,需要改为 out-pointer 方式:

输入路径(Swift → Rust 传 RustBuffer 参数):

  • pushReadingEvent(RustBuffer event) -- 阅读事件上报
  • updateReadingPosition(RustBuffer materialId, RustBuffer position) -- 阅读位置更新
  • readTextStats(RustBuffer filePath) -- 文本统计
  • readImageMeta(RustBuffer filePath) -- 图片元数据
  • detectMaterialType(RustBuffer filePath) -- 文件类型检测
  • searchMarkdownBlocks(RustBuffer blocks, RustBuffer query) -- 搜索
  • searchTextContent(RustBuffer content, RustBuffer query) -- 搜索

输出路径(Rust → Swift 返回 RustBuffer):

  • createNoteAnchor -- 返回 RustBuffer
  • exportPendingEvents -- 返回 RustBuffer
  • detectMaterialType -- 返回 RustBuffer
  • readImageMeta -- 返回 RustBuffer
  • readTextStats -- 返回 RustBuffer
  • searchMarkdownBlocks -- 返回 RustBuffer
  • searchTextContent -- 返回 RustBuffer
  • parseText -- 返回 RustBuffer

临时影响

iOS 端 MaterialReaderViewcollector.open()/collector.close() 已临时注释,因为 pushReadingEvent 仍使用旧的 struct-passing 方式,调用会 crash。

实现方式

参照已修复的 parseMarkdownfrom_bytes 函数,在 Rust 侧新增 out-pointer 版本的 extern "C" 函数,Swift 侧通过 @_silgen_name 声明并调用。

关联

## 背景 在 ARM64 iOS (iPhone 17 Pro Max 模拟器) 上,Swift 与 Rust 之间通过 C ABI 传递 `RustBuffer`(24 字节结构体,u64+u64+*mut u8)时,超过 16 字节的结构体应通过间接指针传递,但 Swift 和 C/Rust 编译器在内存布局上存在不一致,导致跨 FFI 传参时字段损坏。 已验证的修复方案:将结构体参数拆分为独立的 `len`/`data`/`capacity` 等原始类型参数,通过 out-pointer 传递。 ## 已修复的函数 - `parseMarkdown` -- 使用 `ffi_zx_document_ffi_parse_markdown_separate(len, data, out_capacity, out_len, out_data, out_error_code)` - `ffi_zx_document_ffi_rustbuffer_from_bytes` -- 使用 `ffi_zx_document_ffi_rustbuffer_from_bytes_separate(len, data, out_capacity, out_len, out_data)` - `ffi_zx_document_ffi_rustbuffer_free` -- 使用 `ffi_zx_document_ffi_rustbuffer_free_separate(capacity, len, data)` ## 待修复的函数(仍用旧的 struct-passing) 以下 Rust FFI 函数仍然通过结构体传参 `RustBuffer`,需要改为 out-pointer 方式: ### 输入路径(Swift → Rust 传 RustBuffer 参数): - `pushReadingEvent(RustBuffer event)` -- 阅读事件上报 - `updateReadingPosition(RustBuffer materialId, RustBuffer position)` -- 阅读位置更新 - `readTextStats(RustBuffer filePath)` -- 文本统计 - `readImageMeta(RustBuffer filePath)` -- 图片元数据 - `detectMaterialType(RustBuffer filePath)` -- 文件类型检测 - `searchMarkdownBlocks(RustBuffer blocks, RustBuffer query)` -- 搜索 - `searchTextContent(RustBuffer content, RustBuffer query)` -- 搜索 ### 输出路径(Rust → Swift 返回 RustBuffer): - `createNoteAnchor` -- 返回 RustBuffer - `exportPendingEvents` -- 返回 RustBuffer - `detectMaterialType` -- 返回 RustBuffer - `readImageMeta` -- 返回 RustBuffer - `readTextStats` -- 返回 RustBuffer - `searchMarkdownBlocks` -- 返回 RustBuffer - `searchTextContent` -- 返回 RustBuffer - `parseText` -- 返回 RustBuffer ## 临时影响 iOS 端 `MaterialReaderView` 中 `collector.open()`/`collector.close()` 已临时注释,因为 `pushReadingEvent` 仍使用旧的 struct-passing 方式,调用会 crash。 ## 实现方式 参照已修复的 `parseMarkdown` 和 `from_bytes` 函数,在 Rust 侧新增 out-pointer 版本的 `extern "C"` 函数,Swift 侧通过 `@_silgen_name` 声明并调用。 ## 关联 - iOS 项目:https://git.longde.cloud/wangdl/ios-projects - 本仓库文件:`crates/zx_document_ffi/src/lib.rs` - Swift 绑定:`bindings/ios/generated/zx_document.swift`(需 patch)
Author
Owner

进度汇报 (2026-06-05)

根因确认

ARM64 iOS 上 Swift ↔ Rust 之间传递 RustBuffer(24 字节结构体)存在 ABI 兼容性问题:

  • 输入路径(Swift→Rust):ForeignBytes 结构体字段被错误读取(读到 markdown 文本内容而非指针)
  • 输出路径(Rust→Swift):返回的 RustBuffer 的 capacity/len/data 字段损坏

已验证的修复方案

将结构体参数拆分为独立的原始类型参数(Int32/UnsafeRawPointer/UInt64),通过 out-pointer 传递。

已修复

函数 新 FFI 函数
parseMarkdown ffi_zx_document_ffi_parse_markdown_separate(len, data, ...)
rustbuffer_from_bytes ffi_zx_document_ffi_rustbuffer_from_bytes_separate(len, data, ...)
rustbuffer_free ffi_zx_document_ffi_rustbuffer_free_separate(capacity, len, data)

待修复

剩余约 10 个函数仍用旧 struct-passing(pushReadingEventreadTextStatsreadImageMetadetectMaterialTypesearchMarkdownBlockssearchTextContentupdateReadingPositionexportPendingEventscreateNoteAnchorclearExportedEventsparseText

临时影响

iOS MaterialReaderView.onAppear 中 collector 调用已注释(因 pushReadingEvent 仍用旧 API 会 crash)

状态

🟡 parseMarkdown 路径已修复并验证通过,剩余函数待下一轮集中转换。

## 进度汇报 (2026-06-05) ### 根因确认 ARM64 iOS 上 Swift ↔ Rust 之间传递 `RustBuffer`(24 字节结构体)存在 ABI 兼容性问题: - 输入路径(Swift→Rust):`ForeignBytes` 结构体字段被错误读取(读到 markdown 文本内容而非指针) - 输出路径(Rust→Swift):返回的 `RustBuffer` 的 capacity/len/data 字段损坏 ### 已验证的修复方案 将结构体参数拆分为独立的原始类型参数(`Int32`/`UnsafeRawPointer`/`UInt64`),通过 out-pointer 传递。 ### 已修复 | 函数 | 新 FFI 函数 | |------|------------| | `parseMarkdown` | `ffi_zx_document_ffi_parse_markdown_separate(len, data, ...)` | | `rustbuffer_from_bytes` | `ffi_zx_document_ffi_rustbuffer_from_bytes_separate(len, data, ...)` | | `rustbuffer_free` | `ffi_zx_document_ffi_rustbuffer_free_separate(capacity, len, data)` | ### 待修复 剩余约 10 个函数仍用旧 struct-passing(`pushReadingEvent`、`readTextStats`、`readImageMeta`、`detectMaterialType`、`searchMarkdownBlocks`、`searchTextContent`、`updateReadingPosition`、`exportPendingEvents`、`createNoteAnchor`、`clearExportedEvents`、`parseText`) ### 临时影响 iOS `MaterialReaderView.onAppear` 中 collector 调用已注释(因 `pushReadingEvent` 仍用旧 API 会 crash) ### 状态 🟡 `parseMarkdown` 路径已修复并验证通过,剩余函数待下一轮集中转换。
Author
Owner

关闭

ARM64 ABI 已修复 — out-pointer _separate 函数实现

## 关闭 ARM64 ABI 已修复 — out-pointer _separate 函数实现
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wangdl/zhixi-document-runtime#36
No description provided.