菜鸟教程小白 发表于 2022-12-12 15:17:32

ios - A64 : objc_msgSend crashes while performSelector:withObject: works


                                            <p><p>我正在尝试调试 iOS 上的崩溃,该崩溃在支持 <a href="http://en.wikipedia.org/wiki/ARM_architecture#64.2F32-bit_architecture" rel="noreferrer noopener nofollow">A64 instruction set</a> 的设备上始终如一地重现。 .特别是使用 <a href="http://en.wikipedia.org/wiki/Apple_A7" rel="noreferrer noopener nofollow">A7</a> 的 iPad/<a href="http://en.wikipedia.org/wiki/Apple_A8X" rel="noreferrer noopener nofollow">A8X</a> SoC 的。在任何 32 位 iPad 上运行时,完全相同的代码也将始终<em>不会</em>崩溃(如果我将构建限制为仅 32 位架构,然后在支持 64 位的 iPad)。 </p>

<p>崩溃报告为 <code>EXC_BAD_ACCESS</code>,触发它的代码没有什么特别花哨的:</p>

<pre><code>if (object &amp;&amp; ) {
    objc_msgSend(self, addSelector, object);                  //EXC_BAD_ACCESS on A64 devices!
    //;   //no crash
}
</code></pre>

<p>违规行是 <code>objc_msgSend(self, addSelector, object);</code>。第一个令人困惑的部分是,如果我将这一行替换为 <code>;</code>,一切都会正常运行(尽管它给我留下了令人讨厌的“PerformSelector 可能导致泄漏。 ..“警告)。除非我完全误解了某些东西,否则 <code>objc_msgSend</code> 和 <code>performSelector:withObject:</code> 在这种情况下应该基本上是等效的。 </p>

<p>那么为什么一个会崩溃(并且仅在使用 A64 时)而另一个不会?</p>

<p>下一个令人费解的事情是在崩溃发生时尝试调试它。 <code>self</code> 和 <code>object</code> 都是 <code>NSManagedObject</code> 实例,我可以在调试器中观察到它们都是有效对象。但是,异常总是报告为:</p>

<p><code>-:无法识别的选择器发送到实例 0x...</code></p>

<p>调用显示为源自 <code>CoreData</code> 的内部,我无法给出任何合理的解释来说明这是如何发生的,尤其是从32 位到 64 位架构/构建。 </p>

<p>对于导致此类问题的原因有什么想法吗?还是我应该只使用那个 <code>performSelector:withObject:</code> 并感到高兴?</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><blockquote>
<p>and there&#39;s nothing particularly fancy about the code that triggers it</p>
</blockquote>

<p>如您所见,直接调用 <code>objc_msgSend()</code> <em>是</em>花哨的,而且很难正确地做到这一点。</p>

<blockquote>
<p>The first perplexing part is that if I replace this line with ;, everything works as it should</p>
</blockquote>

<p>是的。因为这些都不一样。</p>

<p><code>objc_msgSend*</code> 有多种风格,您需要根据返回类型和处理器选择正确的一种。具体分为三个版本:</p>

<ul>
<li><code>objc_msgSend_fpret</code> -- 浮点返回类型(适用于OS X;我没查过是否适用于64位ARM)</li>
<li><code>objc_msgSend_stret</code> -- 用于结构返回类型(如 <code>CGPoint</code>)</li>
<li><code>objc_msgSend</code> -- 对于其他返回类型</li>
</ul>

<p>如果这在所有处理器上总是<em>完全</em>正确,我不记得了。一些处理器对待“大”结构不同于“小”结构。并且调用约定都是特定于处理器的,这就是为什么您只能在一个处理器上看到它的原因。还记得我说过直接调用 <code>objc_msgSend()</code> 很漂亮吗?</p>

<p>您使用它来调用任意选择器这一事实表明它们中的一些具有结构或浮点返回,在这种情况下,事情将在错误的寄存器中,事情将完全横向发展。</p>

<p>有关此的更多讨论,请参阅 <a href="https://stackoverflow.com/questions/27786033/why-does-the-objective-c-compiler-need-to-know-method-signatures" rel="noreferrer noopener nofollow">Why does the Objective-C compiler need to know method signatures?</a> .</p>

<blockquote>
<p>Are there any ideas on what would cause this kind of issue? Or should I just go with that performSelector:withObject: and be happy?</p>
</blockquote>

<p>正如警告所说,<code>performSelector:</code> 可能会泄漏,因为 ARC 不知道如何对其进行内存管理。解决方案是重新设计它以使用 block 而不是选择器。如果您必须使用选择器,并且您确定这里调用的选择器都不会返回对象,请参阅 <a href="https://stackoverflow.com/a/7933931/97337" rel="noreferrer noopener nofollow">https://stackoverflow.com/a/7933931/97337</a>有关如何使警告静音。如果这些可以返回对象,那么你需要确保它们不能有额外的保留,这只是一个你可能不应该下去的兔子洞(或者至少应该作为一个新问题提出)。</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - A64 : objc_msgSend crashes while performSelector:withObject: works,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/30218810/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/30218810/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - A64 : objc_msgSend crashes while performSelector:withObject: works