0

我正在处理现有的大型代码库,在将 iOS SDK 升级到 4.1 后,我现在看到了非常奇怪的行为。问题的症结似乎是一个将不再分配的特定类——它在 obj_msgSend 中引发了错误的访问,并且似乎是 objc_msgSend 不喜欢的堆栈上的 Class 对象——尽管它实际上不是 NULL。

原来的失败线如下所示:-

tileProjection = [[RMFractalTileProjection alloc] initFromProjection:proj tileSideLength:sideLength maxZoom:18];

我解构了这个以隔离问题:-

RMFractalTileProjection *p = [RMFractalTileProjection alloc];  // <- this crashes
p = [p initFromProjection:proj tileSideLength:sideLength maxZoom:18];
tileProjection = p;

然后我尝试了这个: -

Class c = NSClassFromString(@"RMFractalTileProjection");
assert(c);
NSLog( @"RMFractalTileProjection class(ptr) %p", c );  // <- prints an address OK
NSLog( @"RMFractalTileProjection class(obj) %@", c );  // <- crashes

在调试器中,看起来 Class 对象是合理的,但是 NSLog 在尝试打印它时会崩溃。

需要注意的一件事:有问题的类声明如下,我不确定协议是否导致问题。因为这个特定部分是一大块开源代码,所以很难删除这个协议要求,看看这是否会产生影响。

@interface RMFractalTileProjection : NSObject<RMMercatorToTileProjection>
{
 ...
}

对此的任何帮助都非常感谢 - 这是一个表演停止者。

谢谢

4

3 回答 3

1

好的,终于找到了。正如 Jeremy 建议的那样,这被证明是一个常规的记忆障碍。

我发现它的困难在于,被踩踏的不是 Class 对象本身,而是类的元类结构——这是一个普通的 Class 对象,但上一层,由类“isa”指针引用。这就是为什么当我在调试器中检查该类时它看起来不错的原因——我需要跟踪 isa 指针并将内存转储到上一层才能找到它。对我来说幸运的是,这个类只是 NSObject 的一个子类——如果它被深度子类化,这可能会更难找到。在咬紧牙关、对 objc_msgSend 进行逆向工程、准确计算堆栈帧上的内容并遵循所有指针之后,我得到了第一个线索。是的,艰难的方式:)

Matt Gallaghar 的帖子(以及我通过以下链接找到的其他各种帖子)在帮助我通过这个迷宫方面非常宝贵 - 谢谢大家!

在这方面花了很多时间,但从好的方面来说,在过去的一天半里,我学到了很多关于 Objective C 内部原理的东西 :)

于 2010-09-17T11:22:13.300 回答
1

这不是一个真正的答案,而是一些前进的想法。

目前想到的唯一原因是内存损坏和某种链接问题。也许您正在以某种方式链接该课程的两个版本。

假设是类,让它在 alloc 中崩溃似乎没有什么问题。没有 +initialize 或任何东西。

我会问自己并试图回答的问题是:

如果我重命名课程会发生什么?

如果我创建一个具有不同名称的新的相同类会发生什么?

传递给 obj_msgSend 的指针:合理吗?它是否指向看起来像一个类的东西?

您是否曾经子类化该类并且您是否在子类上使用了初始化?

指针总是一样的吗?如果是这样,您可以查看它指向的内容并查看它在执行过程中是否发生了变化。

如果你把自己送到课堂会发生什么?

于 2010-09-16T13:39:34.183 回答
0

感谢 JeremyP 的这些建议——在你整天敲打键盘之后,有新的建议总是好的!

您创建具有相同名称的相同类的建议似乎已经解决了这个问题。我不知道为什么,我觉得我需要了解这里发生了什么。没错,这听起来像是某种链接器问题,但我仍然不知道是什么导致了如此严重的运行时错误,甚至在构建时都不会产生警告。

回覆。指针,它看起来确实是合理的,但是类中的某些东西最终被取消引用为 objc_msgSend 中的空指针。有时,在我更改代码并重建后,我会得到一个空指针。这种行为显然暗示了一些非确定性的东西,比如记忆跺脚。

我会发布我的发现。

于 2010-09-16T19:57:06.290 回答