与 CTRun 和 CTRunGetPositions 相关的崩溃问题

问题描述 投票:0回答:1

我遇到了一个特殊的问题。在很多年前的一个项目中,有这样一段代码:

func testFunc() {
 // ......
 let runs = CTLineGetGlyphRuns(finalLine) as! [CTRun]
 if let truncationRun = runs.last {
     var truncationPosition = CGPoint.zero
     CTRunGetPositions(truncationRun, CFRange(location: 0, length: 0), &truncationPosition)
     var truncationAscent: CGFloat = 0, truncationDescent: CGFloat = 0
     let truncationWidth = CTRunGetTypographicBounds(truncationRun, CFRange(location: 0, length: 0), &truncationAscent, &truncationDescent, nil)
     // ......
 }
 // ......

}

当 truncationRun 中的字形数量超过一定值时,函数执行结束后会发生崩溃。这个值在不同的iOS系统上有所不同——在iOS 13上,它是11;在 iOS 15 上,为 7;在 iOS 17 上,它是 8。我不明白为什么会发生这种情况?

当然,如果根据CTRunGetGlyphCount()方法为trancationPosition控件分配空间,则这段代码可以正常运行。

ios core-text
1个回答
0
投票

我假设你的问题是“为什么当运行时间很短时不会发生崩溃?”在一般情况下,此代码肯定会崩溃,因为它尝试将 CGPoint 数组写入为单个 CGPoint 分配的空间中。这会损坏其他内存并导致崩溃。经典的缓冲区溢出。

但至于为什么在某些情况下不会崩溃,很大程度上取决于内存中紧接着

truncationPosition
之后发生的事情。你破坏的记忆里可能什么都没有。它可能包含一些不“重要”的东西。由于对齐要求,它可能是空的。溢出越大,您就越有可能遇到重要的事情或破坏堆栈本身。

但简短的答案是,超出缓冲区的写入是未定义的行为,并且系统不保证它会崩溃。通常它会,但通常它可能只是做奇怪的事情,甚至“起作用”。操作系统版本之间,甚至同一版本上相同代码的运行之间,发生的情况可能会发生变化。

© www.soinside.com 2019 - 2024. All rights reserved.