继承类“无效指针错误”调用虚函数时
正如您在下面的代码中看到的,我有一个抽象基类“HostWindow”,以及从它派生的类“Chrome”。所有功能均在Chrome中实现。问题是,如果 Chrome 中的函数是虚拟的,我无法调用它们。
class HostWindow : public Noncopyable {
public:
virtual ~HostWindow() { }
// Pure virtual functions:
virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false) = 0;
virtual void scrollbarsModeDidChange() const = 0;
}
class Chrome : public HostWindow {
// HostWindow functions:
virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false);
virtual void scrollbarsModeDidChange() const;
void focus() const;
}
假设我们有一个 Chrome 实例,并且调用了几个函数:
WebCore::Chrome *chrome = new Chrome();
chrome->repaint(IntRect(), true); // Null pointer error
chrome->focus(); // returns void (works)
每当我调用虚函数时,我得到的空指针错误是:
程序收到信号EXC_BAD_ACCESS,无法访问内存。 原因:KERN_PROTECTION_FAILURE,地址:0x00000008
知道发生了什么吗?
更新: 正如你们许多人指出的那样 - 这段代码实际上运行了。不幸的是,我无法提供更完整的示例,因为代码位于 WebCore (WebKit) 的深处。不过,我已经缩小了问题范围。如果我手动创建 Chrome 实例,则可以调用虚拟函数。所以问题出在这个特定的 chrome 实例上 - 它无法正确实例化。现在,Chrome 实例在另一个类的构造函数中实例化。我将进一步调查...
更新 2: 好的,检查有问题的实例上的 vtable 表明它是空的;来自GDB:
p *(void **)chrome
$52 = (void *) 0x0
一个普通的实例有一个正确的vtable。所以,我必须弄清楚为什么 vtable 为零 - 我想知道这是怎么发生的?也许是因为它正在其他一些类构造函数中实例化?
更新3: 看起来我对这个问题的看法是正确的,因为它是在另一个类的构造函数中实例化的。
因此,在实例化之前,它看起来像这样:
Page::Page(ChromeClient* chromeClient, ...)
: m_chrome(new Chrome(this, chromeClient))
m_chrome 是一个无效实例,具有 nil vtable。 我已经更改了实例化,因此它会在第一次需要变量时发生(这涉及保存 ChromeClient 以供以后使用):
Page::Page(ChromeClient* chromeClient, ...)
: m_chrome(0)
, m_chrome_client(chromeClient)
Chrome* Page::chrome() const {
if(!m_chrome) {
m_chrome = new Chrome(this, m_chrome_client);
}
return m_chrome;
}
现在 Page::chrome() 实例是正确的实例,具有正确的 vtable - 相当奇怪!
更新4: 最后一次更新,我保证:)。好的,所以我已经准确地指出了它。如果您在 Page 构造函数的主体中实例化它,您将获得带有 vtable 的正确实例。如果你在 Page 构造函数的头部实例化它,它没有 vtable。在构造函数头部可以进行的变量设置类型是否有任何限制?我想这是另一个 Stackoverflow 问题。
谢谢你们这么有帮助。
As you can see in the code below, I have an Abstract Base Class "HostWindow", and class that derives from it "Chrome". All the functions are implemented in Chrome. The issue is, I can't call functions in Chrome if they're virtual.
class HostWindow : public Noncopyable {
public:
virtual ~HostWindow() { }
// Pure virtual functions:
virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false) = 0;
virtual void scrollbarsModeDidChange() const = 0;
}
class Chrome : public HostWindow {
// HostWindow functions:
virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false);
virtual void scrollbarsModeDidChange() const;
void focus() const;
}
So lets say we have an instance of Chrome, and we call a few functions:
WebCore::Chrome *chrome = new Chrome();
chrome->repaint(IntRect(), true); // Null pointer error
chrome->focus(); // returns void (works)
The null pointer error I get whenever I call virtual functions is:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000008
Any idea what's happening?
Update:
As many of you pointed out - this code actually runs. Unfortunately I can't provide a more full example, since the code is deep inside WebCore (WebKit). However, I have narrowed the problem down. If I create a Chrome instance manually, calling virtual functions work. So the issue is with this particular chrome instance - it can't instantiated properly. Now, the Chrome instance is instantiated in a constructor of another class. I'll investigate further...
Update 2:
Ok, examining the vtable on the offending instance shows that it's null; from GDB:
p *(void **)chrome
$52 = (void *) 0x0
A normal instance has a correct vtable. So, I've got to work out why the vtable is nil - I wonder how that could happen? Maybe because it's being instantiated in some other classes Constructor?
Update 3:
Looks like I'm correct about the issue being it's instantiation inside another class' constructor.
So, before the instantiation looked like this:
Page::Page(ChromeClient* chromeClient, ...)
: m_chrome(new Chrome(this, chromeClient))
And m_chrome is an invalid instance, with a nil vtable.
I've changed the instantiation so it happens when the first time the variable is needed (this involves saving ChromeClient for later):
Page::Page(ChromeClient* chromeClient, ...)
: m_chrome(0)
, m_chrome_client(chromeClient)
Chrome* Page::chrome() const {
if(!m_chrome) {
m_chrome = new Chrome(this, m_chrome_client);
}
return m_chrome;
}
Now the Page::chrome() instance is the correct one, with the proper vtable - rather odd!
Update 4:
Last update, I promise :). Ok, so I've pinpointed it down exactly. You get the correct instance, with the vtable, if you instantiate it in Page constructor's body. If you instantiate it in Page constructor's head, it doesn't have a vtable. Is there any limitation in the types of variable setting you can do in a constructor's head? I guess that's another Stackoverflow question.
Thanks guys for being so helpful.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
是的,“this”指针为零。加 8 得到偏移量,这就是你的错。显然你根本没有任何实际的物体。
我猜,因为您还没有发布足够的代码来真正掌握。要么整个 this 指针为 0,要么虚拟函数表指针为 0,可能是因为该对象在创建之后、尝试调用之前已被删除。
我能给你的最好建议是制作一个更小的试管。要么你会发现你的问题,要么你最终会得到一个可发布的示例。
在构造过程结束之前,vtbl 才在实例中到位。事实上,规范要求逐步修改 vtbl 以匹配类层次结构的构造状态。
Yes, the 'this' pointer is zero. Add 8 to get an offset, and there's your fault. You apparently don't have any actual object at all.
Since you haven't posted enough code to really come to grips, I'm guessing. Either the entire this pointer is 0, or the virtual function table pointer is 0, perhaps because the object has been deleted after it was created and before you try to call it.
The best advice I can give you is to create a much smaller test-tube. Either you will find your problem or you will end up with a postable example.
The vtbl isn't in place in an instance until the end of the construction process. In fact, the spec requires progressive modification of the vtbl to match the state of construction of the class hierarchy.
可以贴出完整的代码吗?
对代码进行轻微修改(无论可用的内容)后,它可以工作:
Can you post the complete code?
After slight modification in your code(whatever is available), it works :
我不熟悉您拥有的代码库,但您不应该编写以下内容:
而不是:
I'm not familiar with the code base you have, but shouldn't you write the following:
instead of:
假设你的不可复制如下(至少对我来说是这样),
在将 public 修饰符插入类 chrome 的函数以及它们的一些虚拟实现之后,整个过程没有出现任何问题。
最后,检查分配失败。 (是的,“新”是在堆上分配)
ssume your non-copyable are as following (at least for mine did)
after inserting public modifier to class chrome's function and some dummy implementation for them, the whole thing worked without stated problem.
lastly, DO checking for allocation failure. (yes, "new" are allocation on heap)
我发现这是由于允许导出所有符号造成的。
通常,WebCore 仅导出符号的子集 - 基本上是 WebKit 需要的东西。
我更改了它以导出每个符号 - 它以某种方式导致了这个错误。
I found that this was being caused by allowing all symbols to be exported.
Usually, WebCore only has a subset of symbols exported - basically on things that WebKit needs.
I changed that to export every symbol - and it somehow caused this error.